一、注意作用域
避免全局查找:全局变量的查找肯定比局部的开销更大,因为要涉及到作用域链上的查找。
解决办法:若需要对document的引用,创建一个指向document的局部变量。
例如:
1 function updateUI(){ 2 var imgs=document.getElementByTagsName('img'); 3 for(var i=0,len=imgs.length;i<len;i++){ 4 imgs[i].title=document.title+i; 5 } 6 } 7 //如果有很多图片的话就要引用全局变量document很多遍,每次都进行作用域链的查找.性能肯定好不了。 8 //就像你要在一个大房间里找一个小东西一样,每次都要从头到尾找一遍。太辛苦。
//既然找的很辛苦,那么,我先把它的具体位置写在一张纸条上,放入一个 2 //离我最近盒子里去,下次找的话,在盒子里面取就 3 //好了(按照位置直接去找,不用走弯路) 4 function updateUI(){ 5 var doc=document;//纸条入盒子 6 var imgs=doc.getElementByTagsName('img'); 7 for(var i=0,len=imgs.length;i<len;i++){ 8 imgs[i].title=document.title+i; 9 } 10 } 11 //现在就节省了好多麻烦(优化性能)
避免with语句:原理跟上面差不多,with会增加执行代码中作用域链的长度。额外的作用域链的查找,速度肯定就慢了。
function updatebody(){ with(document.body){ innerHTML='helllo world!'; } } //全局查找
function(){ var body=document.body; body.innerHTML='hello world!' } //储存在局部变量中,避免了全局查找
二、选择正确方法
避免不必要的属性查找
这里正确的方法可以说是解决问题的算法和方法。
一般算法越复杂,执行的时间越长。列举几中算法:
O(1) | 常数 | 不管值多少,执行的时间是一定的:一般是简单的值和储存在变量中的值 |
O(log n) | 对数 | 总执行时间和值得数量有关 |
O(n) | 线性 | 总执行时间和值得数量直接相关:遍历数组中的所有元素 |
O(n2) | 平方 | 总执行时间和值得数量有关,每个值至少获取n次 |
注意:获取常量和访问数组元素属于O(1),效率比获取对象属性(需要先在原型链中对拥有该名称的属性进行查找)要高。
多次用到同一个属性时,存在局部变量中。
优化循环
1 减值迭代:从最大值开始,而不是0
2 简化终止条件:每次循环都要计算终止条件,避免O(n)操作
3 简化循环体:确保没有可以容易移除循环的密集计算
4 使用后测试循环:避免最初终值条件的计算。(这种情况要保证至少有一个处理的值)
如果这些都做到了,就只能优化process()函数了
展开循环
process(values[0]);
process(values[1]);
process(values[2]);
这样避免了建立循环和处理终值条件的额外开销,是代码运行更快。
如果迭代次数不能定用Duff装置技术
避免双重解释
容易产生的地方:eval()函数 Function()构造函数 setTimeout() 都会造成双重解析,而实例化一个新的解析器开销很大。
解决方法:尽量避免用eval()函数
函数写成一般的函数,函数字表达式,函数声明。
setTime 中传入函数作为第一个参数而不是包含js代码的字符串。
其他需要注意的地方
1 原生方法较快(用c/c++语言写出来的比js快)
2 Switch语句较快(可以代替大量使用if-else的时候)
3 按位运算符较快
三、最小化语句数
单语句多操作比多语句但操作快,这句话的意思是,能写成一个语句就不要写成两个语句。比如说:
1 多变量声明的时候
var i=5; var color='purple'; var values=[1,2,3]; //可以写成 var i=5,color='purple',values[1,2,3];
2 插入迭代
var name=values[i]; i++; //换成这样 var name=values[i++];
3 定义数组和对象时尽量使用字面量。这样可以消除不必要的语句。(代码就不展示了,脑补吧。)
四、优化DOM交互
1 最小化现场更新
浏览器需要计算尺寸进行更新,所以越少越好
var list=document.getElementById('list'); var item,i; for(i=10;i>=0;i--){ item=document.createElement('li'); list.appendChild(item); item.appendChild(document.creatTextnode('item'+i)); } //可以通过创建片段来减少现场更新 var list=document.getElementById('list'); fragment=document.createDocumentFragment(); var item,i; for(i=10;i>=0;i--){ item=document.createElement('li'); fragment.appendChild(item); item.appendChild(document.creatTextnode('item'+i)); } list.appendChild(fragment);
2 需要大量创建DOM节点的时候,用innerHTML比createElement()和appendChild()快。
var list=document.getElementById('list'); html=''; for(i=10,i>=0;i--){ html+='<li>item'+i+'</li>'; } list.innerHTML='html';
3 使用事件代理(前面有一篇说过这个)
4 注意HTMLcollection
要尽量减少HTMLcollection的访问
var imags=document.getElementsByTagName('img'); for(var i=0,len=imags.length;i<len;i++){ //处理 } //将HTMLcollection的length属性存入一个局部变量,以后访问这个局部变量就可以了
这里说一下会产生HTNLcollection的地方
1 getElemenstByTagName()
2 childNodes
3 attributes
4 document.forms document.images
终于总结完了(js高级程序设计)。。。以前写代码还真的没有考虑这么多,以后要把这些思想融入自己的代码中,养成一个好的习惯。