说到作用域啊就很容易想到作用域链(scope chain),我们知道要搜索一个变量,所在的执行环境都要沿着这条作用域向上搜索这个变量,作用域链上有很多的变量,那么我们就得遍历,遍历就需要时间啊,而且你越往上查找所需时间越多,如果我们能减少这个时间,我们代码执行效率不是可以提高了吗?
好聪明啊,ok,我看看有哪些方式可以减少这个时间:
2.1 避免全局查找
这是性能优化的一重点,上面也说了,越往上查找时间越多,也就是说查找全局变量和函数比局部要多!看代码:
function updateUI(){ var imgs = document.getElementByTagName('img'); for(var i = 0 ,lng = imgs.length;i < lng;i ++){ imgss[i].title = document.title + 'image' + i; } var msg = docuement.getElementById('msg'); msg.innerHTML = 'update complete.'; }
这代码很正常呀!我之前也经常这么做滴。但是我们细心可以发现,这段代码有三处引用了全局变量document,如果我们的页面很多图片,那么在for循环中的document就会被执行上百次,而每次都要需要在作用域链中查找,时间都去哪了,我还没......停!。
我们可以通过在函数中创建一个局部变量保存对document的引用,这样,我们在函数里任何地方引用document都不用跑到全局变量去找了。这样就改进了代码的性能,看代码:
function updateUI(){ var doc = document; // 将document保存在局部变量doc中 var imgs = doc.getElementByTagName('img'); for(var i = 0 ,lng = imgs.length;i < lng;i ++){ imgss[i].title = doc.title + 'image' + i; } var msg = doc.getElementById('msg'); msg.innerHTML = 'update complete.'; }
所以啊,我们在开发中,如果在函数中会经常用到全局变量,把它保存在局部变量中!
2.2 避免使用with语句
用with语句延长了作用域,查找变量同样费时间,这个我们一般不会用到,所以不展开了。解决方法还是和上面的例子一样,将全局变量保存在局部变量中!
3.优化循环
循环在编程中可谓家常便饭,在js中也随处可见,循环体会反复地执行同一段代码,执行时间一直累加,所以能够对循环体的代码进行优化也可以大大减少执行时间!如何优化?四种方式。
3.1 减值迭代
我们写迭代器(循环条件)的时候一般都这样(var i = 0;i < 10;i ++),从0开始,增加到某个特定值。然而在很多情况下,如果在循环中使用减值迭代器效率更高。我测试了下,如果循环体不复杂的话,两者差不多!
//增值迭代 --效率较低 for(var i = 0;i < items.length;i++){ doSomething(items[i]); } //减值迭代 --效率较高 for(var i = items.length - 1;i >= 0;i--){ doSomething(items[i]); }
3.2 简化终止条件
由于每次循环都会计算终止条件,所以必须保证它的执行尽可能地块。这里主要是避免其他DOM元素及其属性的的查找。
//看终止条件,每次循环都需要查询items及其length属性 for(var i = 0;i < items.length;i++){ doSomething(items[i]); } //将items.length的值保存在局部变量lng中。 for(var i = 0,lng = items.length;i < lng;i++){ doSomething(items[i]); }
3.3 简化循环体
原因和上面以上的,所以在循环体内避免大量的密集的操作。
这其实和上面讲的:1.1 最小化现场更新 。是一样的优化方式。可以倒回去看看。
4.基本的算法优化
在计算机中,算法的复杂度用O表示。下面是javascript中几种常见的算法类型:
O(1) :常数,不管有多少值,执行的时间都是恒定的,比如简单值和存储在变量中的值。
O(log n):对数,总的执行时间和数量有关,但不一定要获取每一个值,如:二分法查找
O(n) :线性,总执行时间和数量直接相关,如:遍历
O(n*n) :平方,总执行时间和数量有关,每个值至少获取N次,如:插入排序
ok,有了上面的知识,我们就可以对javascript进行一些算法上的优化了。看代码:
var value = 5; var sum = value + 10; alert(sum);
这段代码进行了4次常量值的查找:数字5,变量value,数字10,变量sum,这段代码的算法复杂度就是O(1)。又如:
var value = [10,5]; var sum = value[0] + value[1]; alert(sum);
在javascript中访问数组元素也是一个O(1)操作,和简单的变量查找效率一样。再看:
var value = {one:10,two:10}; var sum = value.one + value.two; alert(sum);
要表达的是访问对象上的属性要比访问数组和变量的效率低。因为这是一个O(n)操作。你需要在对象的原型链中查找该属性,所花时间较多。