深入理解JavaScript系列(4):作用域链
在《深入理解 JavaScript 系列(2):执行上下文栈》中提到,当 JavaScript 代码执行代码时,就会创建一个执行上下文。
对于执行上下文,都有三个重要属性:
- 变量对象 (Variable Object - VO)
- 作用域链
- this
我们来介绍一下作用域链。
作用域链
在查找变量的时候,会先从当前上下文的变量对象中查找,如果没找到,就会从上一级的执行上下文的变量对象中查找,直到找到全局对象为止。
而这样由多个执行上下文的变量对象构成的链表就时作用域链。
函数创建
每一个函数都有自己的作用域,内部有一个 [[scope]]
属性,当函数创建时,就会保存所有父级变量对象到其中,简单来说,[[scope]]
就是所有父级变量对象的层级链。
注意:[[scope]]
并不能代表完整的作用域链。
我们来看一个例子吧
1 | function fn1() { |
函数创建时,我们来看看每一个函数的 [[scope]]
为:
1 | fn1.[[scope]] = [ |
函数激活
当函数激活时,进入函数上下文,创建 VO/AO
后,就会将活动对象添加到作用域链的前端。
在执行上下文中,我们将作用域链命名为 Scope
1 | Scope = [AO].concat([[Scope]]); |
我们来举个例子吧,对《JavaScript 权威指南》 中的例子进行修改
1 | var name = 'hzq'; |
来看看执行过程吧
- 创建 checkname 函数
1 | checkname.[[scope]] = [ |
- 创建 checkname 函数执行上下文,并将 checkname 函数执行上下文压入执行上下文栈
1 | ECStack = [checknameContext, globalContext]; |
- checkname 函数分析阶段 - 复制函数[[scope]]属性创建作用域链,并进行
AO
的创建。如何创建看《深入理解 JavaScript 系列(3):变量对象》。
1 | checknameContext = { |
- 将活动对象压入 checkname 作用域链顶端
1 | checknameContext = { |
- 开始执行函数
1 | checknameContext = { |
- 返回
name
,在一开始就找到了,所有直接返回该值,函数执行完毕。函数上下文弹出执行上下文栈。
1 | ECStack = [globalContext]; |
相关文章推荐
-------------------- 本文结束
感谢阅读 --------------------