数据存取与DOM编程

  1. 数据存取
    1. 管理作用域
      1. 作用域链和标识符解析
      2. 标识符解析的性能
      3. 改变作用域链
      4. 动态作用域
    2. 闭包,作用域和内存
    3. 原型链与嵌套成员

数据存取

一般数据的存储位置是很影响性能的,但是 JS 的问题相对简单,因为可选方案比较少。但是存储位置很大程度影响读取速度。

  • 字面量:只代表本身,不存储在特定位置,比如字符串,数字,布尔,对象,数组,函数,正则等,null,undefined。
  • 本地变量:使用 var 定义的存储单元
  • 数组元素:存在数组对象内部,数字作为索引
  • 对象成员:存在 js 对象内部,字符串作为索引

一般字面量和本地变量的存取性能基本可以忽略,数组元素和对象成员的稍微高一些。具体的实现也是看浏览器的,比如 FF 对于数组的性能进行了优化,也会很快,但是一般对象成员的损耗是最高的。

管理作用域

作用域很重要,不只是性能,还有功能的角度。

作用域链和标识符解析

JS 函数是一个对象,是 Function 对象的实例。

与其他对象一样,既拥有可以编程访问的属性,还有一系列仅供JS引擎存取的内部属性,比如[[scope]]。

[[scope]]包含了一个函数被创建的作用域中对象的集合,这个集合被称之为函数的作用域链。如果是一个全局对象,那么作用域链就会插入一个指向全局对象的一个指针,可以访问到全局中的所有对象。

执行函数时会创建一个执行环境,每次执行函数都会创建执行环境。

每个执行环境都有自己的作用域链,当执行时,他的作用域链初始化为[[scope]]的作用域链,然后创建一个包含了所有局部变量(包括参数,this)的”活动对象”,添加到作用域链的最顶层。当执行完成,执行环境被销毁,活动对象也随之销毁。

每次进行变量的查找时,都会从执行环境作用域链的顶部(活动对象)开始查找,正是这个搜索的过程影响了性能。

标识符解析的性能

很明显,变量埋得越深,查找越需要消耗性能。

解决方法也比较简单,就是跨作用域的值如果访问了多次的话,就用一个局部变量存储起来

改变作用域链

with 语句 与 try–catch 语句
with 是可以延长作用域链的,就是说使用了 with 之后,这个对象的所有属性放入一个变量对象,然后放置到了作用域链的顶部。

try…catch 语句的 catch 也是可以延长作用域链,异常对象会被放入变量对象,然后放到作用域的顶部

注意这里是临时被改变的,catch 或者 with 语句一旦执行结束,作用域链就会变回原来的状态。

我们可以把 catch 语句里面的错误委托给一个函数来处理。由于只执行了一条语句,而且没有局部变量访问,作用域的临时改变就不会影响代码性能。

动态作用域

with,try–catch,和 eval 都是动态的作用域,有些浏览器的优化是没法支持动态作用域的。

闭包,作用域和内存

闭包是外部函数被执行的时候创建的。

外部函数被执行时,他会创建自己的活动对象,然后加到自己的作用域链中。闭包会被创建,作用域链初始化为外部函数的活动对象以及全局对象。然后闭包被执行的时候,又会往自己的作用域链中推入自己的活动对象。

一般情况下,函数执行完成,执行环境与活动对象就会被销毁,这里由于闭包仍然拥有外部函数活动对象的引用,所以暂时无法回收。注意 IE 由于使用非原生 Js 对象来实现 DOM,因此会导致内存泄漏(勐喆说 IE 不能搞定循环依赖)(说是 DOM 对象被回收了,JS 对象可能没法回收,导致内存的泄露)

比如:

function a() {
  function b() {}
  return b;
}
//到这里啥都不执行,a的作用域链为全局,b还未被创建
var c = a(); //执行过程中a的作用域链为a的活动对象+全局,c即为b,作用域链为a的活动对象+全局。执行完a的执行环境销毁,但是a的活动对象还存在,因为c引用着。
c(); //这样子执行,c的作用域链为c的活动对象+a的活动对象+全局;执行完了,执行环境被销毁,c的作用域链为a的活动对象+全局,所以a的活动对象就不会被回收
//除非脚本执行完了,或者手动设置为null,或者简单地用个自定义匿名函数包起来。
a()(); //这样子执行,执行完了所有的活动对象,作用域就被销毁了

所以闭包的内存问题其实是由于不正确的使用导致的。但是我们用个匿名函数包起来也能够结果,就怕那种循环嵌套的,会导致内存可能会泄露。

原型链与嵌套成员

原型链的访问同理,需要遍历原型链,所以埋得越深当然性能会消耗的越多

嵌套成员一样,window.location.href 肯定是比 location.href 慢的

就是尽量避免读取同一个对象属性,用局部变量来保存一下。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 981909093@qq.com

文章标题:数据存取与DOM编程

文章字数:1.4k

本文作者:泽鹿

发布时间:2019-08-28, 16:45:23

最后更新:2019-08-28, 16:45:23

原始链接:http://panyifei.github.io/2019/08/28/读书笔记/高性能Javascript/2章数据存取/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏