计算机科学中有一个经典问题是通过改变数据的存储位置来获得最佳的读写性能,数据存储的位置关系到代码执行过程中数据的检索速度。
在JS中,数据的存储位置会很大程度上影响其读取速度,JS中有下面四种基本的数据存取位置。
(1)字面量
(2)本地变量
(3)数组元素
(4)对象成员
大多数情况下,从一个字面量和一个局部变量中存取数据的性能差异是微不足道的。访问数组元素和对象成员的代价则更高一些,至于具体高出多少,很大程度上取决于浏览器。
有以下几种方法来规避问题以及优化代码:
1. 管理作用域
在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取或存储数据。
该过程中,会搜索执行环境的作用域链,搜索每一个标识符。正是这个搜索过程,影响了性能。
2. 标识符解析的性能。
标识符解析是有代价的,事实上没有哪种计算机操作可以不产生性能开销。
在执行环境的作用域链中,一个标识符所在位置越深,它的读写速度也就越慢。因此,函数中读写局部变量总是最快的,而读写全局变量总是最慢的。
3. 改变作用域链
一般来说,一个执行环境的作用域链是不会改变的。但是,有两个语句可以在执行时临时改变作用域链。
第一个是with语句,但是不建议使用,因为with语句会创建一个新的作用域,增加了作用域链访问代价。
第二个是try catch语句,
4. 动态作用域
无论是with语句还是try-catch的catch子句,或是包含eval()的函数,都被认为是动态作用域。
动态作用域只存在于代码执行过程中,因此无法通过静态分析(查看代码结构)检测出来。
不建议使用动态作用域,请尽量避免。
5. 闭包、作用域和内存
闭包允许函数访问局部作用域之外的数据。不过,JS执行退出执行环境后,闭包中创建的对象不会被销毁,这意味着会需要更多的内存开销。
6. 对象成员
7. 嵌套成员
对象成员嵌套越深,读取速度就会越慢。执行location.href总是比window.location.href要快,后者也比 window.location.href.toString()更快。
8. 缓存对象成员值(其实,主要目的就是减少解析时搜索的作用域链长度,避免重复查找)
总结:通过改变数据存储位置来提高代码性能:
(1) 访问字面量和局部变量的速度最快,访问数组和对象成员相对较慢。
(2) 尽量避免创建全局变量。
(3) 避免使用with和try-catch。
(4) 减少嵌套对象成员。
(5) 属性或方法在原型链中位置越深,访问他的速度就越慢。
(6) 缓存局部变量,减少搜索时作用域链长度。