字符和正则表达式
字符串连接
标准的方式都是A+B通过+进行连接,如果是下面这种写法:
str += 'one' + 'two';
这段代码会经历四个步骤:
- 先在内存中创建一个新的临时字符串(内容为空)
- one和two先进行连接并赋值给临时字符串
- 临时字符串与str进行连接
- 返回的值赋值给str
如果我们这样写可以避免创建临时字符串
str += 'one';
str += 'two';
因为只有一个字符串需要添加,然后str本身就是字符串,所以只对str进行了操作,没有再去创建新的临时字符。
但是这样写太过麻烦,于是可以这样写:
str = str + 'one' + 'two';
因为字符的操作是从=符号开始,从左到右操作,此时str本身是一个占据在内存中的字符串,所以无需创建新的临时字符,然后依次往右连接,最后赋值,为此可以加快速度。
但是在ie7及更早的版本,这种方式反倒没有加速的效果,反而会增加用时,原因是ie每次连接的时候都会每进行一步就复制一次,先将str和one连接的结果复制一次,复制一次后再复制后面的two,然后再将这两个连接的结果复制一次,依次 重复,所以在旧版的ie中,使用+=反倒更快了。
但是+=也不能说明就是ie的最佳方案,在大量文字连接中,+=也是很慢,但是我们可以通过数组项合并的方式提高速度。
数组项合并
Array.prototype.join方法是将数组中的分隔符改变成其他的值,我们可以通过去除这个分隔符达到合并数组的效果,但是这个方法实际上在现在浏览器中是一个比较慢的方法,在旧版的ie反倒可以达到意料之外的效果。
var str = 'I',
strs = [],
num = 5000,
newStr = null;
while(num--) {
strs.push(str);
}
newStr = strs.join('');
这样写反倒快于用for循环str+ ‘I’的方法。当然也仅限于旧版的ie。
正则表达式
正则表达式的优化要首先明白他的工作原理,最主要的就是理解回溯。
回溯就是当正则匹配到一定的值后会继续查找正则后面的值,比如/.*\s+/;首先正则会贪婪的将所有字符匹配到,然后进行回溯,也就是从最后一个字符往前查找,当找到一个\s是并不会立即放弃,它还会继续回溯,直到找不到\s字符了。
如果是惰性模式/.*?\s+/,它的方式又不一样了,惰性可以理解为最少次数,所以他会从最开始一个一个字符回溯,找到一个\s后并不会立即停止,它还会继续查找,直到后面的字符不是\s后才会停止。
使用不明确的正则容易造成回溯失控,你可以把回溯理解为路口,当你到了一个站点后,就会根据实际情况产生多个不同的选择,每个选择为一个路口,当正则在第一个路口找不到的时候就会返回到第二个路口,然后无限重复,直到找到了值或者全部路口都找不到才会停下,所以说,能找到的正则时间最短,找不到的正则是最慢的,因为他要不断的回溯。
为此宽泛的正则性能往往不如更具体的选择,.*往往不如[white]这种实际指出的值,然后我们还可以通过一些位置符减少回溯的次数,比如\b、\B这种。
var str = 'AAAAAAAAAAAAAAAAAAAAAAAAAA';
var reg = /A+A+B/g;
var time = +new Date();
alert(reg.test(str) +' ' + (+new Date() - time))
这段代码中,如果str没有最后的B字符,正则依旧会不断的重复回溯很多次,A+A+会产生众多的路口,为此我们要考虑到一种情况,就是当str中没有B的时候该怎么办?
这里我们就可以使用预查?!
var str = 'AAAAAAAAAAAAAAAAAAAAAAAAAA';
var reg = /A+A+(?=B)B/g;
var time = +new Date();
alert(reg.test(str) +' ' + (+new Date() - time))
通过这个预查可以减少回溯的点,因为预查已经判断到了A+A+的部分,后面是要有B的,那么正则就不会再一个个判断,为此减少了时间,alert输出的时候,你会发现使用之前的正则返回1毫秒的时间,而使用预查的只用了0毫秒,速度非常之快,如果在大量文本内容的时候,预查的优势也会很高,但是不能滥用,预查也是可以进行一定的优化的。
捕获
正则中的捕获()也就是分组会将里面的内容额外的保存起来,如果大量不用的捕获,会浪费内存的空间,为此可以使用非捕获来减少空间占用。
/^[a-z]+(?:.*)/
通过非捕获?:来达到减少占用。
事实上预查虽然是一个(),但是他是非捕获性的,所以他不能被回调所调用。
何时不使用正则
其实这里主要是因为正则只能从开始匹配到末尾,没办法从末尾匹配到开头,哪怕你使用了$字符申明,但是他依旧是从前到后,所以如果是针对末尾的操作,使用其他方法会更快。
比如去除文字末尾的空白字符
var str = 'isdjaajda ',
reg = /\s/,
end = str.length - 1;
while(reg.test(str.charAt(end))) {
end-- ;
}
str = str.slice(0,end+1);
string的操作方法,位置是从0开始计数的,然后获取的是该位置的左边,0 = |i;用|表示获取的位置,于是end就等于文字的length-1获得最后一位的位置,最后当end判断到不是空白字符时,end实际上等于|a这里,使用slice获取区间时要拿到最后一个a,所以end+1。
slice获取到就是末尾没有空白字符的值,如果你使用正则的话想对来说会比较慢一些,特别是前面很多字符的情况。
混合解决方法
正则开头匹配很快,后面很慢,那么就可以混合使用,达到优化的效果
function trim(str) {
var str = str.replace(/^\s+/,''),
end = str.length -1,
reg = /\s/;
while(reg.test(str.charAt(end))) {
end--;
}
return str.slice(0,end + 1);
}
trim(' isdjaajda ');
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据