函数作用域链和闭包(摘自--高性能JavaScript)

每一个js函数都表示为一个对象,确切地说,是Function对象的一个实例。Function对象拥有可以编程访问的属性,和一系列不能通过代码访问而仅供js引擎存取的内部属性。其中的一个内部属性[[Scope]],它包含了一个函数被创建的作用域中对象的集合。这个集合被称为函数的作用域链,它决定哪些数据能被函数访问。函数作用域中的每个对象被称为一个可变对象,每个可变对象都以“键值对”的形式存在。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的对象所填充。

执行函数时会创建一个称为执行环境的内部对象。一个执行环境定义了一个函数执行时的环境。函数每次执行时对应的执行环境是独一无二的,所以多次调用同一个函数就会创建多个执行环境。函数执行完毕,执行环境就被销毁。每个执行环境都有自己的作用域链,用于解析标识符。当执行环境被创建时,它的作用域链初始化为当前运行函数的[[Scope]]属性中的对象。这些值按照它们的出现在函数中的顺序被复制到执行环境的作用域链中。这个过程完成后,一个称为“活动对象”的新对象就为执行环境创建好了。活动对象作为函数运行时的变量对象,包含了所有局部变量,命名参数,参数集合以及this。然后此对象被推入作用域的最前端。当执行环境被销毁,活动对象也随之销毁。

闭包的[[Scope]]属性包含了与执行环境作用域链相同的对象的引用。通常来说,函数的活动对象会随着执行环境一同销毁。但是引入闭包时,由于引用仍然存在于闭包的[[Scope]]属性中,因此激活对象无法被销毁。这意味着脚本中的闭包与非闭包函数相比,需要更多的内存开销。

当闭包代码执行时,会创建一个执行环境,它的作用域链与属性[[Scope]]中所引用的两个相同的作用域链对象一起被初始化,然后一个活动对象为闭包自身所创建。

图1.函数assignEvents()执行环境的作用域链和闭包

图2.闭包执行环境的作用域链

 

 

对象通过一个内部属性(__proto__)绑定到它的原型。对象可以有两种成员类型:实例成员(直接存在于对象实例中),原型成员(从对象原型继承而来)。

 

 

图3:原型链

posted @ 2017-10-18 22:40  筱悦  阅读(195)  评论(0编辑  收藏  举报