原文 https://developers.google.com/speed/articles/optimizing-javascript
客户端的javascript可以使你的app更加灵活与动态变化,但是浏览器解释代码时,可以引入低效率,而且各个浏览器的区别也很大。如下我们将讨论一些优化javascript代码的方法。
var veryLongMessage =
'This is a long string that due to our strict line length limit of' +
maxCharsPerLine +
' characters per line must be wrapped. ' +
percentWhoDislike +
'% of engineers dislike this rule. The line length limit is for ' +
' style purposes, but we don't want it to have a performance impact.' +
' So the question is how should we do the wrapping?';
Working with strings
字符串的连结能够引起IE6和7垃圾回收的性能问题。尽管在IE8中,这个问题已经被解决了,甚至比其他浏览器更加高效,譬如chrome。但是有很多用户仍然在使用IE6,这个问题应该注意。
取代连结,采用join
var veryLongMessage =
['This is a long string that due to our strict line length limit of',
maxCharsPerLine,
' characters per line must be wrapped. ',
percentWhoDislike,
'% of engineers dislike this rule. The line length limit is for ',
' style purposes, but we don't want it to have a performance impact.',
' So the question is how should we do the wrapping?'
].join();
同样,通过条件或者循环方式以连结的方式建立string是非常低效的。错误的方式如下
var fibonacciStr = 'First 20 Fibonacci Numbers';
for (var i = 0; i < 20; i++) {
fibonacciStr += i + ' = ' + fibonacci(i) + '';
}
正确的方式为:
var strBuilder = ['First 20 fibonacci numbers:'];
for (var i = 0; i < 20; i++) {
strBuilder.push(i, ' = ', fibonacci(i));
}
var fibonacciStr = strBuilder.join('');
Buildingstrings with portions coming from helper functions
以传stringbulder方式建立string,注意的是避免临时string的产生。例如,假设buildMenuItemHtml_
能够把变量转化为string。不好的代码如:
var strBuilder = [];
for (var i = 0, length = menuItems.length; i < length; i++) {
strBuilder.push(this.buildMenuItemHtml_(menuItems[i]));
}
var menuHtml = strBuilder.join();
良好的代码为:
var strBuilder= [];
for(var i = 0, length = menuItems.length; i < length; i++) {
this.buildMenuItem_(menuItems[i],strBuilder);
}
varmenuHtml = strBuilder.join();
Definingclass methods
如下code的效率很低,每当baz.Bar的实例a被构造,foo的函数以及闭包随之产生
baz.Bar = function() {
// constructor body
this.foo = function() {
// method body
};
}
更好的方法为:
baz.Bar =function() {
//constructor body
};
baz.Bar.prototype.foo= function() {
//method body
};
Initializinginstance variables
把变量的声明以及初始化放到实例的prototype里,以此避免当构造函数被调用时,变量每次都被初始化
foo.Bar = function() {
this.prop1_ = 4;
this.prop2_ = true;
this.prop3_ = [];
this.prop4_ = 'blah';
};
采用如下的code
foo.Bar =function() {
this.prop3_= [];
};
foo.Bar.prototype.prop1_= 4;
foo.Bar.prototype.prop2_= true;
foo.Bar.prototype.prop4_= 'blah';
Avoidingpitfalls with closures
闭包的缺点如下:
· They are the most common source of memory leaks.
· Creating a closure is significantly slower then creating aninner function without a closure, and much slower than reusing a staticfunction. For example:
function setupAlertTimeout() {
varmsg = 'Message to alert';
window.setTimeout(function(){ alert(msg); }, 100);
}
效率低于
function setupAlertTimeout() {
window.setTimeout(function(){
varmsg = 'Message to alert';
alert(msg);
},100);
}
效率低于
function alertMsg() {
varmsg = 'Message to alert';
alert(msg);
}
functionsetupAlertTimeout() {
window.setTimeout(alertMsg,100);
}
var a = 'a';
functioncreateFunctionWithClosure() {
varb = 'b';
returnfunction () {
varc = 'c';
a;
b;
c;
};
}
varf = createFunctionWithClosure();
f();
当f被调用了,a比b慢,他们都比c慢。