Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript -- 作用域链 #6

Open
mt51 opened this issue Oct 22, 2018 · 0 comments
Open

JavaScript -- 作用域链 #6

mt51 opened this issue Oct 22, 2018 · 0 comments

Comments

@mt51
Copy link
Owner

mt51 commented Oct 22, 2018

作用域链

这篇文章来讨论一下执行上下文中的另一个属性,作用域链。作用域链的本质是一个指向变量对象的指针列表。

函数的生命周期

函数的生命周期可以分为两个部分:函数创建和函数激活(即函数调用)。

函数创建
前面的文章我们知道,每个执行上下文都会有对应的变量对象。全局环境的变量对象一直存在,直到程序关闭。而函数中的局部的变量对象则是在函数执行的时候才会创建,函数执行结束后销毁。

在函数创建的时候,会预先创建一个包含上一级执行上下文变量对象的作用域,该作用域会保存在内部属性[[Scope]]中。这也意味着函数外部的作用域是在函数创建的时候就已经确定下来的,并且不会改变。

函数激活阶段

在函数激活阶段,也就是当调用一个函数的时候,会进入该函数的执行上下文,此时通过复制将函数的[[Scope]]属性来构建当前环境的作用域。随后在函数中的活动对象AO创建完成之后被推入当前执行上下文的最前端,构成该函数的作用域链。

简单的来说:一个函数的作用域链,是由函数的活动对象和函数的内部属性[[Scope]]构成,用伪代码描述:

Scope = [AO, [[Scope]]]

举个例子:

var x = 10
function foo () {
 console.log(x)   
}
function bar () {
    var x = 20
    foo() // 10
}
bar()

第一步,在创建函数的时候,先查找到当前所在的变量对象,很明显这里的变量对象是VO,也就是全局对象,将其存储在函数内部的[[Scope]]属性中,所以此时

foo.[[Scope]] = [VO]
bar.[[Scope]] = [VO]

第二步,当调用bar的时候,先复制bar.[[Scope]]来构建bar执行上下文的作用域链,此时

Scope = [bar.[[Scope]]] = [VO]

随后,bar的活动对象创AO(bar)建完成之后,此时将AO推入作用域链

Scope = [AO(bar), Scope] = [AO, VO]

至此,函数bar的作用域链构建完成。

调用foo的时候和上面的流程类似,最终foo的作用域链如下:

Scope = [AO(foo), VO]

由于在函数foo中查找不到变量x,所以会沿着作用域链向上查找,因此最终输出的是10

总结

  • 函数的[[Scope]]属性是在函数创建的时被存储下来的,并且是静态不变的,直到函数销毁。
  • [[Scope]]属性是所有父变量对象的层级链

参考

http://www.cnblogs.com/TomXu/archive/2012/01/18/2312463.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant