对象令人感兴趣的一点是用它们解决问题的方式。ECMAScript中最常见的一个问题是字符串连接的性能。与其他语言类似,ECMAScript的字符串是不可变的,即它们的值不能改变。考虑下面的代码:
var str="hello ";
str+="world";
实际上,这段代码在幕后的执行步骤如下:
1)创建存储"hello "的字符串.
2)创建存储"world"的字符串.
3)创建存储连接结果的字符串.
4)把str的当前内容复制到结果中.
5)把"world"复制到结果中.
6).更新str,使它指向结果.
每次完成字符串连接都会执行步骤2到6,使得这种操作非常消耗资源。如果重复这一过程几百次,甚至几千次,就会造成性能问题。解决方法是用Array对象存储字符串,然后用join()方法(参数是空字符串),创建最后的字符串。想象用下面的代码代替前面的代码:
var arr=new Array;
arr[0]="hello ";
arr[1]="world";
var str=arr.join("");
这样,无论在数组中引入多少字符串都不成问题,因为只有在调用join()方法的时候才会发生连接操作。此时,执行的步骤如下:
1)创建存储结果的字符串.
2)把每个字符串复制到结果中的合适位置。
虽然这种解决方法很好,但是还有更好的方法。问题是这段代码不能确切反映出它的意图。要使它更容易理解,可以使用StringBuffer类打包该类的功能。
function StringBuffer() {
this._strings_ = new Array;
};
StringBuffer.prototype.append = function (str) {
this._strings_.push(str);
};
StringBuffer.prototype.toString = function () {
return this._strings_.join("");
};
var buffer = new StringBuffer();
buffer.append("hello ");
buffer.append("world");
var result = buffer.toString();
alert(result);
可以使用下面代码测试StringBuffer对象和传统字符串连接方式的性能:
var d1 = new Date();
var str = "";
for (var i = 0; i < 1000000; i++) {
str += "text";
}
var d2 = new Date();
document.write("Concatenation with plus: " + (d2.getTime() - d1.getTime()) + " milliseconds");
var oBuffer = new StringBuffer();
d1 = new Date();
for (var i = 0; i < 1000000; i++) {
oBuffer.append("text");
}
var sResult = buffer.toString();
d2 = new Date();
document.write("<br/>Concatenation with StringBuffer: " + (d2.getTime() - d1.getTime()) + " milliseconds");
测试结果发现,在IE9中“+=”的效率要比StringBuilder效率高,但是在FF和Chrome下面结果相反,并且得出一个结论,IE运算的速度比FF要慢得多,由于本篇不讨论浏览器内核,所以暂不深究。正常情况下使用StringBuilder要节省50%~150%的时间。