本文是阅读《高性能JavaScript》一书后,从 数据存取 模块对JavaScript性能优化做了部分总结,记录一下。可能总结的不好,不是很完整,也希望各位大佬能多给出一些建议。万分感谢!
作用域和标识符解析
每个js函数都表示一个对象,是Function对象的一个实例,拥有可以变成访问的属性和一系列不能通过代码访问而仅供JS引擎存取的内部属性,其中一个属性就是[[Scope]]
内部属性[[Scope]]包含了一个函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链。这个全局对象代表着所有在全局范围内定义的变量。包含诸如window,navigation和document等。
执行函数时会创建一个称为执行环境的内部对象。一个执行环境定义了一个函数执行时的环境。函数每次执行时对应的执行环境都是独一无二的,所以多次调用同一个函数就会导致创建多个执行环境。当函数执行完毕,执行环境就被销毁。
每个执行环境都有自己的作用域链,用于解析标识符。当执行环境被创建时,它的作用域链初始化为当前运行函数的[[Scope]]属性中的对象。这些值按照它们出现在函数中的顺序被复制到执行环境的作用域链中。这个过程一旦完成,一个被称为“活动对象”的新对象就为执行环境创建好了。活动对象作为函数运行时的变量对象,包含所有局部变量,命名参数,参数集合以及this。然后此对象被推入作用域链的最前端。当执行环境被销毁,活动对象也随之销毁
标识符解析的性能
标识符解析是有代价的,在执行环境的作用域链中,一个标识符所在的位置越深,它的读写速度也就越慢,因此,函数中读写局部变量总是最快的,而读写全局变量通常是最慢的。全局变量总是存在于执行环境作用域链的最末端,因此它也是最远的。
改变作用域链
改变作用域链会导致访问对应对象的作用域时很快,但访问局部变量却变慢了
避免使用with
尽量在catch中将错误委托给一个函数来处理
在确实有必要时才推荐使用动态作用域
闭包、作用域和内存
- 闭包有可能会导致内存泄漏
对象成员
- 访问对象成员的速度比访问字面量和变量要慢,在某些浏览器中比访问数组元素还要慢
原型链
- 对象在原型链中存在的位置越深,存取速度也就越慢
嵌套成员
- 对象成员嵌套的越深,读取速度就会越慢
缓存对象成员
- 在同一个函数或作用域下没必要多次读取同一个对象成员,可以在第一个读取时将对象成员缓存到局部变量中
小结
访问字面量和局部变量的速度最快,相反,访问数组元素和对象成员相对较慢
由于局部变量存在于作用域链的起始位置,因此访问局部变量比访问跨作用于变量更快。变量在作用域链中的位置越深,访问所需的时间越长。由于全局变量总处在作用域链的最末端,因此访问速度也是最慢的
避免使用with语句,因为它会改变执行环境作用域链。同样,try-catch与剧中的catch也有同样的影响,因此也要小心使用
嵌套的对象成员会明显影响性能,尽量少用
属性或方法在原型链中的位置越深,访问它的速度也越慢
通常来说,你可以通过把常用的对象成员、数组元素、跨域变量保存在局部变量中来改善JavaScript性能,因为局部变量访问速度更快