字符串连接

  1. The + operator

    1
    str = "a" + "b" + "c";
  2. The += operator

    1
    2
    3
    str = "a";
    str += "b";
    str += "c";

    str += “one” + “two”;
    会经历4个步骤:

    • 在内存中创建一个临时字符串;。
    • 连接后的字符串”onetwo”被赋予给该临时字符串。
    • 临时字符串与 str 当前的值连接。
    • 结果赋值给 str。

      1
      2
      3
      //这样做直接附加内容给 str,从而避免产生临时字符串。在大多数浏览器中会提速10%-40%
      str += "one";
      str += "two";
      1
      2
      //简化为一个语句
      str = str + "one" + "two";

      但是改变连接顺序(eg: str = “one” + str + “two”;),本优化将失效。

      这些技术不适合 IE。在 IE7 及早期版本中结果只会更慢。是由 IE 执行连接操作的底层机制决定的。

  3. array.join()

    1
    str = ["a", "b", "c"].join("");
    • /

      在大多浏览器中,数项合并比其它字符串连接方法更慢。但事实上,它却在 IE7 及更早版本浏览器中合并大量字符串唯一高效的途径。

  4. string.concat()

    1
    2
    str = "a";
    str = str.concat("b","c");
    • /

      在多数情况下,使用 concat 比使用简单的 + 和 += 稍慢,尤其在 IE、Opera 和 Chrome 中慢得更明显。

正则表达式优化

正则表达式工作原理

  1. 编译
  2. 设置起始位置
  3. 匹配每个正则表达式字元
  4. 匹配成功或失败

回溯

回溯是匹配过程的基础组成部分。
量词,如* +? {2,}
分支,如 | 操作符
贪婪量词:
惰性量词:
? (即匹配尽量少的字符)

回溯失控

当正则表达式导致浏览器假死数秒、数分钟,甚至更长时间,问题很可能是因为回溯失控。
(天呐,我看了书好几遍,还是没搞懂回溯怎么进行的!!)
目标字符串:<p>Para1.</p>
贪婪量词:/<p>.*</p>/i 第16步找到匹配项
惰性量词:/<p>.*?</p>/i 第22步找到匹配项
解决方案:

  1. 具体化
    尽可能具体化分隔符直接的字符串匹配模式。如模式“.?”,它用来匹配一个由双引号包围的字符串。可以把 .\? 替换为更具体的 [^”\r\n]*,就去除了回溯时可能发生的几种情况。
  2. 使用预查和反向引用的模拟原子组
    支持“原子组”特性的正则表达式引擎,包括.NET、Java、Oniguruma、PCRE 和 Perl。一旦原子组中存在一个正则表达式,该组的任何回溯位置都会被丢弃。
    写法:(?>…)
    But! JavaScript 不支持原子组。但是可以利用预查过程中的行为来模拟原子组:预查也是原子组。

提高正则表达式效率的方法

  1. 关注如何让匹配更快失败
  2. 正则表达式以简单、必需的字元开始
  3. 使用量词模式,使它们后面的字元互斥
  4. 使用非捕获组
  5. 值捕获感兴趣的文本以减少后处理
  6. 暴露必需的字元
  7. 使用合适的量词
  8. 把正则表达式赋值给变量并重用它们
  9. 将复杂的正则表达式拆分为简单的片段

何时不使用正则表达式

只是搜索字面字符串时会弄巧成拙。
如:检查一个字符串是否以分号结尾,可能用如下表达式

1
endsWithSemicolon = /;%/.test(str);

但是浏览器并不是小机灵,它只会逐个测试整个字符串。最好的解决方法是

1
endsWithSemicolon = str.charAt(str.length - 1) == ";";

去除字符串首尾空白

  1. 使用正则表达式去首尾空白
    1
    2
    3
    4
    5
    if(!String.prototype.trim){
    String.prototype.trim = function(){
    return this.replace(/^\s+/,"").replace(/\s+$/,"");
    }
    }

其中有5种方法,这个是更好的解决方案

  1. 不实用正则表达式去除字符串首尾空白
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    String.prototype.trim = function(){
    var start = 0,
    end = this.length - 1,
    ws = " \n\r\t\f\x0b\xa0\u1680......\ufeff";
    while (ws.indexOf(this.charAt(start)) > -1){
    start++;
    }
    while (end > start && ws.indexOf(this.charAt(end)) > -1){
    end--;
    }
    return this.slice(start, end + 1);
    }

弱点:不宜用来处理前后大段的空白字符。

  1. 混合解决方案
    用正则表达式方法过滤头部空白,用非正则表达式的方法过滤尾字符。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    String.prototype.trim = function(){
    var str = this.replace(/^\s+/,""),
    end = str.length - 1,
    ws = /\s/;
    while (ws.test(str.charAt(end))){
    end--;
    }
    return str.slice(0, end + 1);
    }

所有 trim 方法的总的趋势是:在基于正则表达式的方案中,字符串的总长度比修剪掉的字符数量更影响性能;而非正则表达式方案从字符串末尾反向查找,不受字符串总长度的影响,但明显收到修剪空格的数量的影响。
简单地使用2次子正则表达式在各种浏览器处理不同内容及长度的字符串是,提供了更一致的性能表现,所以它被证明是最周全的解决方案。