JS编程建议——36:警惕字符串连接操作(2)

建议36:警惕字符串连接操作(2)
先将两个小字符串合并起来,然后将结果返回给大字符串。创建中间字符串s1 + s2与两次复制大字符串相比,对性能的“冲击”要轻得多。
(2)编译期合并
在赋值表达式中所有字符串连接都属于编译期常量,Firefox自动地在编译过程中合并它们。在以下这个方法中可看到这一过程:

  1. function foldingDemo() {
  2. var str = "compile" + "time" + "folding";
  3. str += "this" + "works" + "too";
  4. strstr = str + "but" + "not" + "this";
  5. }
  6. alert(foldingDemo.toString());alert(foldingDemo.toString());
    在Firefox中我们经常看到这种形式:
  7. function foldingDemo() {
  8. var str = "compiletimefolding";
  9. str += "thisworkstoo";
  10. strstr = str + "but" + "not" + "this";
  11. }
  12. alert(foldingDemo.toString());alert(foldingDemo.toString());
    当字符串是这样合并在一起时,由于运行时没有中间字符串,因此连接它们的时间和内存可以减少到零。这种功能非常了不起,但它并不经常起作用。

(3)数组联结
Array.prototype.join方法将数组的所有元素合并成一个字符串,并在每个元素之间插入一个分隔符字符串。如果传递一个空字符串作为分隔符,可以简单地将数组的所有元素连接起来。
在大多数浏览器上,数组联结比连接字符串的其他方法更慢,但事实上,作为一种补偿方法,在IE 7和更早的浏览器上它是连接大量字符串的唯一的高效途径。例如,下面的示例代码演示了可用数组联结解决的性能问题:

  1. var str = "I'm a thirty-five character string.", newStr = "", appends = 5000;
  2. while(appends--) {
  3. newStr += str;
  4. }
    此代码连接5000 个长度为35 的字符串。执行以上代码后显示在IE 7中执行此测试所需的时间,从5000次连接开始,然后逐步增加连接数量。IE 7的连接算法要求浏览器在循环过程中反复地为越来越大的字符串复制和分配内存,结果是出现以平方关系递增的运行时间和内存消耗。

目前所有其他的浏览器(包括IE 8及其以上版本)在这个测试中表现良好,不会呈现平方关系的复杂性递增,这是真正的改善。然而,此程序演示了看似简单的字符串连接所产生的影响。5000次连接用去226ms已经是一个显著的性能冲击了,应当尽可能地缩减这一时间。锁定用户浏览器长达32 s,只是为了连接20 000 个短字符串,这对任何应用程序来说都是不能接受的。
如果使用数组联结生成同样的字符串,则代码如下:

  1. var str = "I'm a thirty-five character string.", strs = [], newStr, appends = 5000;
  2. while(appends--) {
  3. strs[strs.length] = str;
  4. }
  5. newStr = strs.join("");
    上面代码优化的核心是避免重复的内存分配和复制越来越大的字符串。当联结一个数组时,浏览器宁愿分配足够大的内存用于存放整个字符串,也不会超过一次地复制最终字符串的同一部分。

原生字符串连接函数接受任意数目的参数,并将每一个参数都追加到调用函数的字符串,这是连接字符串最灵活的方法,因为可以利用它追加一个字符串,或者一次追加几个字符串,或者追加一个完整的字符串数组。

  1. strstr = str.concat(s1);
  2. strstr = str.concat(s1, s2, s3);
  3. str = String.prototype.concat.apply(str, array);
    在大多数情况下,concat执行速度比简单的“+”和“+=”慢一些,而且在IE、Opera 和Chrome 浏览器上会大幅变慢。此外,虽然使用concat 合并数组中的所有字符串看起来和前面讨论的数组联结差不多,但是通常它更慢一些(在Opera浏览器上除外),而且它还潜伏着严重的性能问题,这与在IE 7 和更早版本中使用“+”和“+=”创建大字符串情况类似。
时间: 2024-09-14 18:58:14

JS编程建议——36:警惕字符串连接操作(2)的相关文章

JS编程建议——36:警惕字符串连接操作(1)

建议36:警惕字符串连接操作(1)字符串连接表现出惊人的"性能紧张".一个任务通过一个循环向字符串末尾不断地添加内容,以创建一个字符串.例如,创建一个HTML 表或一个XML 文档.此类处理在一些浏览器上表现得非常糟糕.当连接少量字符串时,这些问题都可以忽略,临时使用可选择最熟悉的操作.当合并字符串的长度和数量增加之后,有些函数开始显示出"威力".(1)+.+=+.+=运算符提供了连接字符串的最简单方法.除IE 7及其以前版本外,当前所有浏览器都对这种方法优化得很好

JS编程建议——4:注意JavaScript数据类型的特殊性(1)

建议4:注意JavaScript数据类型的特殊性(1)1.防止浮点数溢出二进制的浮点数不能正确地处理十进制的小数,因此0.1+0.2不等于0.3. num = 0.1+0.2; //0.30000000000000004 这是JavaScript中最经常报告的Bug,并且这是遵循二进制浮点数算术标准(IEEE 754)而导致的结果.这个标准适合很多应用,但它违背了数字基本常识.幸运的是,浮点数中的整数运算是精确的,所以小数表现出来的问题可以通过指定精度来避免.例如,针对上面的相加可以这样进行处理

JS编程建议——1:警惕Unicode乱码

建议1:警惕Unicode乱码ECMA标准规定JavaScript语言基于Unicode标准进行开发,JavaScript内核完全采用UCS字符集进行编写,因此在JavaScript代码中每个字符都使用两个字节来表示,这意味着可以使用中文来命名变量或函数名.虽然ECMAScript v3标准允许Unicode字符出现在JavaScript程序的任何地方,但是在v1和v2中,ECMA标准只允许Unicode字符出现在注释或引号包含的字符串直接量中,在其他地方必须使用ASCII字符集,在ECMASc

JS编程建议——45:警惕嵌套量词和回溯失控

建议45:警惕嵌套量词和回溯失控嵌套量词总是需要额外的关注和小心,以确保没有掩盖回溯失控问题.嵌套量词出现在一个自身被重复量词修饰的组中.嵌套量词本身并不会造成性能危害,只是在尝试匹配字符串过程中,很容易不小心在内部量词和外部量词之间,产生一大堆分解文本的方法.例如,要匹配HTML 标签,使用了下面的正则表达式:/<(?:1|"2"|'3')*>/这也许过于简单,因为它不能正确地处理所有情况的有效和无效标记,但在处理有效HTML 片段时应该没什么问题.与更加简单的/<

JS编程建议——48:慎用正则表达式修剪字符串

建议48:慎用正则表达式修剪字符串(1)使用两个子表达式修剪字符串去除字符串首尾的空格是一个简单而常见的任务,但到目前为止JavaScript 还没有实现它.正则表达式允许用很少的代码实现一个修剪函数,最好的全面解决方案可能是使用两个子表达式:一个用于去除头部空格,另一个用于去除尾部空格.这样处理简单而快速,特别是处理长字符串时.if(!String.prototype.trim) { String.prototype.trim = function() { return this.replac

JS编程建议——8:谨慎使用运算符(1)

建议8:谨慎使用运算符(1)1.用===,而不用==JavaScript有两组相等运算符:===和!==.==和!=.===和!==这一组运算符会按照期望的方式工作.如果两个运算数类型一致且拥有相同的值,那么===返回true,而!==返回false.==和!=只有在两个运算数类型一致时才会做出正确的判断,如果两个运算数是不同的类型,会试图强制转换运算数的类型.转换的规则复杂且难以记忆,具体规则如下: '' == '0' // false 0 == '' // true 0 == '0' //

JS编程建议——29:准确使用循环体(1)

建议29:准确使用循环体(1)1.选择正确的循环体在大多数编程语言中,代码执行时间多数消耗在循环的执行上.在一系列编程模式中,循环是最常用的模式之一,因此也是提高性能必须关注的地方之一.理解JavaScript 中循环对性能的影响至关重要,因为死循环或长时间运行的循环会严重影响用户体验.JavaScript定义了4种类型的循环:第一种循环是标准的for循环,与C语言使用同样的语法: for (var i=0; i < 10; i++){ //循环体 } for循环是最常用的循环结构,它由4部分组

JS编程建议——37:推荐使用replace(2)

建议37:推荐使用replace(2)在上面的示例代码中,函数f()的参数为特殊字符"$1",它表示正则表达式/(bw+b)/中小括号每次匹配的文本.然后在函数体内对这个匹配文本进行处理,截取其首字母并转换为大写形式,之后返回新处理的字符串.replace方法能够在原文本中使用这个返回的新字符串替换每次匹配的子字符串.对于上面的示例,可以使用小括号来获取更多匹配文本的信息.例如,直接利用小括号传递单词的首字母,然后进行大小写转换处理: var s = 'script language

JS编程建议——67:套用函数

建议67:套用函数套用是JavaScript函数一个很有趣的应用.所谓套用就是将函数与传递给它的参数相结合,产生一个新的函数.在函数式编程中,函数本身也是一个值,这种特性允许用户以有趣的方式去操作函数值.例如,在下面代码中定义一个add()函数,该函数能够返回一个新的函数,并把参数值传递给这个新函数,从而实现连加操作.var add = function(n){ return function(m){ return n+m; } }document.writeln(add(2)(3)); //5