一、ECMAScript的字符串是不可变的,即它们的值不能改变,因此当你写出下面的代码的时候发生了什么呢?
var str = "Hello "; str += "world";
?执行的步骤如下:
- 创建存储“Hello“的字符串
- 创建存储”world“的字符串
- 创建存储连接结果的字符串
- 把str的当前内容复制到结果中
- 把“world”复制到结果中
- 更新str,使它指向结果
??? 每次完成字符串的连接都会执行步骤2-6,使得这种操作非常消耗资源。想象一下重复这个过程几百次,甚至几千次,那性能如何?
?
二、那么再看看下面的代码,来解决这种窘况
var arr = new Array; arr[0] = "Hello "; arr[1] = "world"; var str = arr.join("");
执行的步骤如下:
- 创建存储结果的字符串
- 把每个字符串复制到结果中的适当位置
这样,无论数组要引入多少字符串都不成问题,因为只有在调用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
new StringBuffer(); 换成 []
append换成 push
toString 换成 join("")
再试试。
FF下 我测试得结果:
原始的方法加号 拼接10000个字符串 花费时间:15秒
数组拼接10000个字符串 花费时间:14秒
append换成 push
toString 换成 join("")
再试试。
FF下 我测试得结果:
原始的方法加号 拼接10000个字符串 花费时间:15秒
数组拼接10000个字符串 花费时间:14秒
9 楼
qamer
2009-05-05
果然是抱着怀疑一切的态度在看书

10 楼
block
2009-05-05
IE6测试结果:
原始的方法加号 拼接10000个字符串 花费时间:157秒
StringBuffer 拼接10000个字符串 花费时间:78秒
原始的方法加号 拼接10000个字符串 花费时间:157秒
StringBuffer 拼接10000个字符串 花费时间:78秒
11 楼
jessdy
2009-05-06
IE 6
原始的方法加号 拼接10000个字符串 花费时间:453秒
StringBuffer 拼接10000个字符串 花费时间:79秒
CHROME
原始的方法加号 拼接10000个字符串 花费时间:1秒
StringBuffer 拼接10000个字符串 花费时间:4秒
原始的方法加号 拼接10000个字符串 花费时间:453秒
StringBuffer 拼接10000个字符串 花费时间:79秒
CHROME
原始的方法加号 拼接10000个字符串 花费时间:1秒
StringBuffer 拼接10000个字符串 花费时间:4秒
12 楼
jessdy
2009-05-06
IE6
原始的方法加号 拼接10000个字符串 花费时间:516秒
StringBuffer 拼接10000个字符串 花费时间:78秒
Array 拼接10000个字符串 花费时间:47秒
第三种
原始的方法加号 拼接10000个字符串 花费时间:516秒
StringBuffer 拼接10000个字符串 花费时间:78秒
Array 拼接10000个字符串 花费时间:47秒
第三种
var oa = []; tStart = new Date(); for(var i=0;i<10000;i++) { oa.push("text"); } var oRst = oa.join(""); tEnd = new Date(); document.write("<br/>Array 拼接10000个字符串 花费时间:"+(tEnd.getTime()-tStart.getTime())+"秒");
13 楼
elf8848
2009-05-06
引用
果然是抱着怀疑一切的态度在看书
果然是抱着怀疑一切的态度在看书
14 楼
hax
2009-05-06
IE6下字符串拼接慢不是因为字符串创建的关系,而是因为白痴的垃圾回收算法。
15 楼
night_stalker
2009-05-06
还是比较喜欢下面这样的写法(prototype):
buf = [] (10000).times(function(){buf.push("text")}) buf.join("")
16 楼
ydqwtt
2012-09-12
我测试也出现这种情况了,StringBuffer的效率没有+连接字符的效率高呢,有谁知道连接字符串用哪种效率最高啊,在JS中