一.可维护性优化
1.添加注释
注释能够增强代码的可读性以及可维护性,当然,理想情况是满满的注释,但这不太现实。所以我们只需要在一些关键的地方添上注释:
- 函数和方法:尤其是返回值,因为直接看不出来
- 大段代码(功能模块):说明模块功能
- 复杂算法:写出关键点,方便理解
- Hack:说明为了修复什么问题,当前方案是否完善,能否改进
2.“暗示”变量类型
通过初始值来暗示,例如:
3.解耦(分层)
- 结构层:HTML
- 行为层:JS
- 表现层:CSS
尽量不要“越权”,如果实在是想越权,也应该用文档或者注释说明。尽量不要出现紧耦合,例如:
- JS-HTML:
- JS-CSS:
- JS-JS:
避免逻辑耦合的几条原则:
不要传递event对象,只传需要的数据
触发事件不应该是执行动作的唯一方式
事件处理器应该只处理事件相关数据(获取事件源,坐标值等等),然后把处理转交给应用逻辑
4.编码原则
- 尊重对象所有权,不要随便修改别人的对象,具体要求:
- 不要给实例/原型添加属性或方法
- 不要重写已存在的方法
可选方案:
- 组合:创建实现了所需功能的新对象,引用需要的对象
- 继承:创建自定义类型,继承需要修改的类型,然后添加额外功能
- 用命名空间避免全局变量,例如:
- 用常量提高可维护性,例如:
注意:常量包括常用的CSS类名和其它任何可能影响维护的值
二.性能优化
1.避免长作用域链查找
把需要多次引用的全局变量另存为局部变量
2.尽量不要用with语句
with语句会延长作用域,存在长作用域查找的开销,可以用另存局部变量来代替(没有with方便,但多少能好一点)
3.避免不必要的属性查找
- 尽量把重复使用的值另存为局部变量,例如:
- 优化循环
- 减值迭代更快(i–)
- 简化终止条件,每次循环都会检查终止条件,简化条件能提高效率
- 简化循环体,尽量减少循环体里面的计算量
- 使用后测试循环(do...while),可以避免第一次循环前的判断
- 展开循环如果循环次数确定,最好不要用循环,因为循环存在创建循环和处理终止条件的额外开销,例如:
如果循环次数不能确定,可以用Duff技术(Tom Duff发明的)展开一部分循环,提高效率,例如:
或者另一个更快的Duff方法:
- 避免双重解释
双重解释是指:用js解析js。具体是用eval()函数或者new Function(strCode)或者setTimeout(strCode)
双重解释的缺点:需要再启动一个解析器来解析,存在很大的开销,比直接解析慢很多 - 原生方法更快
原生方法是用用C/C++编译好的模块,所以要快得多 - switch比if-else快
- 位运算并没有更快
在其它语言中把数学运算简化为位运算能够提升计算速度,但js中没这一说,因为js内部只有一种数值类型(double),所以做位运算需要折腾:double – int – 做位运算 – double,性能可想而知 - 减少语句数量
- 用1个var声明多个变量
- 插入迭代值,arr[i++]一条语句搞定,不用把i++独立成一个语句
- 用数组/对象字面量,代码行数明显变少了
- DOM优化
- 减少现场更新,可以用DocumentFragment优化
- 用innerHTML创建DOM节点比创建一堆节点再组装要快,但存在JS-HTML耦合问题,慎重考虑
- 用事件委托
- 注意实时更新的集合(NodeList、NamedNodeMap、HTMLCollection)
除了把引用另存为局部变量外,还要注意访问其属性也是需要重新查询的,比如:var imgs = document.images;访问imgs.length也需要再查一次
三.发布优化
- 用验证工具(如JSLint)检查代码,发现语法错误之外的潜在问题
- 去掉注释(出于安全性考虑)
- 合并js文件,尽量减少外部文件数量
- 压缩代码(如YUI压缩器),减少代码本身大小,也可以同时混淆代码,提高安全性,但混淆代码本身存在风险,可能引发错误
- 开启服务器压缩功能,例如gzip模块