日期:2014-05-16  浏览次数:20505 次

如何摆脱JS糟糕的字符串连接,我掉进了陷阱

一、ECMAScript的字符串是不可变的,即它们的值不能改变,因此当你写出下面的代码的时候发生了什么呢?

var str = "Hello ";
str += "world";

?执行的步骤如下:

  1. 创建存储“Hello“的字符串
  2. 创建存储”world“的字符串
  3. 创建存储连接结果的字符串
  4. 把str的当前内容复制到结果中
  5. 把“world”复制到结果中
  6. 更新str,使它指向结果

??? 每次完成字符串的连接都会执行步骤2-6,使得这种操作非常消耗资源。想象一下重复这个过程几百次,甚至几千次,那性能如何?

?

二、那么再看看下面的代码,来解决这种窘况

var arr = new Array;
arr[0] = "Hello ";
arr[1] = "world";
var str = arr.join(""); 

执行的步骤如下:

  1. 创建存储结果的字符串
  2. 把每个字符串复制到结果中的适当位置

这样,无论数组要引入多少字符串都不成问题,因为只有在调用join()方法时候才会发生连接操作。

?

三、觉得操作很复杂?代码不能确切反应它的意图?那么我们用对象的解决方式吧,使它更容易理解,用StringBuffer类来封装该功能:

function StringBuffer() {
    this._strs = new Array;
}

StringBuffer.prototype.append = function (str) {
    this._strs.push(str);
};

StringBuffer.prototype.toString = function() {
    this._strs.join("");
};

??? 好了,感受一下吧,现在如何操作字符串呢?

var sb = new StringBuffer();
sb.append("Hello ");
sb.append("world");
var result = sb.toString();

?

四、似乎色香味俱全了,但是吃下去的功效如何?

var tStart = new Date();
var str = "";
for(var i=0;i<10000;i++)
{
   str += "text"
}
var tEnd = new Date();

document.write("原始的方法加号 拼接10000个字符串 花费时间:"+(tEnd.getTime()-tStart.getTime())+"秒");


var oSB = new StringBuffer();
tStart = new Date();
for(var i=0;i<10000;i++)
{
    oSB.append("text");
}
var sRst = oSB.toString();
tEnd = new Date();

document.write("<br/>StringBuffer 拼接10000个字符串 花费时间:"+(tEnd.getTime()-tStart.getTime())+"秒");

?

?? 可能你已经猜到了,StringBuffer要比+快,到底快多少呢?我的测试结果:

?

?

FF3.0.10
原始的方法加号 拼接10000个字符串 花费时间:3豪秒
StringBuffer 拼接10000个字符串 花费时间:8豪秒 

IE7
原始的方法加号 拼接10000个字符串 花费时间:15豪秒
StringBuffer 拼接10000个字符串 花费时间:16豪秒 

IE8
原始的方法加号 拼接10000个字符串 花费时间:15豪秒
StringBuffer 拼接10000个字符串 花费时间:16豪秒

Chrome1.0.154.46
原始的方法加号 拼接10000个字符串 花费时间:1豪秒
StringBuffer 拼接10000个字符串 花费时间:2豪秒

?

五、怎么回事?

?

??? 恩?眼睛花了?还是测试结果贴错了?还是……?

?

??? 一切都没有错!

?

??? 2006年11月此书出版《JavaScript高级程序设计》在84-85页,就是我上面的内容,我的测试结果却和它的完全相反,技术的变革还是……?

?

??? 我觉得是一个教训!深刻的教训!不知道哪看了这篇文章的人会有何感想。

?

1 楼 playfish 2009-05-02  

呵呵,因为书出得比较早的关系吧.06年的时候,主要的浏览器是IE6跟FF2.

如果你拿到IE6下面去测试,你就会真正发现问题.

IE6执行字符串拼接的实现,是错误的,注意,是错误,而不仅仅是bug.这导致IE6在执行字符串操作时候的效率极其低下.而我们通常谈的js性能优化,大部分其实都是在对IE6做优化.


你看书看起来还是挺认真的嘛,呵呵.

2 楼 wh8766 2009-05-03  
楼主的研究精神值得学习 赞下
3 楼 iammonster 2009-05-03  
呵呵,5.1有点时间,把经常用的东西,翻了翻
4 楼 cloudgamer 2009-05-03  
不说还真不知道
不过也正常,原作者写的时候距今估计也好几年了
当年的“高级”现在也已经成了入门了
5 楼 mating 2009-05-03  
是吗?不是一直说StringBuffer快吗!难道效率没+高!不会吧!我记得上次javaEye还有个人发个帖子说数据量大的话还是用StringBuffer啊!
6 楼 kaipingk 2009-05-04  
js 里面叶有 StringBuffer?
7 楼 kaipingk 2009-05-04  
kaipingk 写道

js 里面叶有 StringBuffer?

不好意思,看漏了
8 楼 jianyi.hh 2009-05-04