避免二次解析
Function 构造函数可以接收任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。来看下面的例子:
var sum = new Function(“num1”, “num2”, “return num1 + num2”); // 不推荐
技术角度讲,这是一个函数表达式。但是,我们不推荐读者使用这种方法定义函数,因为这种语法会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。包括 eval 也会解析两次。
避免 with 语句
在性能非常重要的地方必须避免使用 with 语句。和函数类似, with 语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度。由于额外的作用域链查找,在 with 语句中执行的代码肯定会比外面执行的代码要慢。
function updateBody(){
with(document.body){
alert(tagName);
innerHTML = “Hello world!”;
}
}
使用对象/ 数组直接量
在 JavaScript 中有多种方法创建对象和数组,但没有什么比创建对象和数组直接量更快了。如果不使用直接量,典型的对象创建和赋值是这样的:
var myObject = new Object();
myObject.name = "Nicholas";
myObject.count = 50;
虽然在技术上这种做法没有什么不对,直接量赋值很快。作为一个额外的好处,直接量在你的代码中占用较少空间,所以整个文件尺寸可以更小。上面的代码可用直接量重写为下面的样式:
var myObject = { name: "Nicholas", count: 50 };
不要重复工作
在计算机科学领域最重要的性能优化技术之一是避免重复工作。避免重复工作的概念实际上意味着两件事:不要做不必要的工作,不要重复做已经完成的工作。
也许最常见的重复工作类型是浏览器检测。大量代码依赖于浏览器的功能。以事件的添加为例,典型的跨浏览器代码如下:
function addHandler(target, eventType, handler){
if (target.addEventListener){ //DOM2 Events
target.addEventListener(eventType, handler, false);
} else { //IE
target.attachEvent("on" + eventType, handler);
}
}
乍一看,这些函数为实现它们的目的已经足够优化。隐藏的性能问题在于每次函数调用时都执行重复工作。每一次,都进行同样的检查,看看某种方法是否存在。
延迟加载
一种消除函数中重复工作的方法称作延迟加载。延迟加载意味着在信息被使用之前不做任何工作。在前面的例子中,不需要判断使用哪种方法,直到有人调用此函数。使用延迟加载的函数如下:
function addHandler (target, eventType, handler) {
//判断 function
if (target.addEventListener) { //DOM2 Events
addHandler = function (target, eventType, handler) {
target.addEventListener(eventType, handler, false);
};
} else { //IE
addHandler = function (target, eventType, handler) {
target.attachEvent("on" + eventType, handler);
};
}
addHandler(target, eventType, handler);
}
这个函数依照延迟加载模式实现。这个方法第一次被调用时,检查一次并决定使用哪种方法附加。然后,原始函数就被包含适当操作的新函数覆盖了。最后调用新函数并将原始参数传给它。以后再调用 addHandler()
时不会再次检测,因为检测代码已经被新函数覆盖了。
位操作运算符
JavaScript 中的数字按照 IEEE-754 标准 64 位格式存储。在位运算中,数字被转换为有符号 32 位格式。每种操作均直接操作在这个 32 位数上实现结果。尽管需要转换,这个过程与 JavaScript 中其他数学和布尔
运算相比还是非常快。