-
Notifications
You must be signed in to change notification settings - Fork 4
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
關於 JS 作用域裡面的解釋 #1
Comments
@aszx87410 首先,函数执行环境(Executation Context, EC)的确是在函数调用的时候创建的,而且每次调用时创建的执行上下文也是相互独立的。文章提到,执行上下文包括 3 个东西:变量对象(VO)或活动对象(AO),作用域链和 this。VO/AO 存储了当前函数内定义的所有变量、对象、函数以及形参等;this 与函数的调用方式相关;关于作用域链,很抱歉我没有完整详述,以下谈一谈作用域链。 作用域链虽然作为执行上下文的一部分,但却并不是等到执行上文创建时,它才开始创建的。一条完整作用域链可以认为分成两部分(无论是时间还是空间上),以下我以你的例子作为素材。 function giveMeClosure() { // line1
var count = 0 // line2
function closure() { // line3
console.log(count++) // line4
} // line5
return closure // line6
} // line7
// line8
var func = giveMeClosure() // line9
func() // line10 首先,每个函数都有一个 [[Scope]] 内部属性,它表示了这个函数被创建时所处的环境,在函数定义时就已经明确。[[Scope]] 的内容就是当前函数定义时,所处的执行上下文的作用域链。以上面程序为例, giveMeClosureEC = {
AO: {
arguments:{
length: 0
},
count: 0,
closure: Point to the function definition
},
scopeChain: [giveMeClosure.AO, globalEC.VO],
this: value of this
} ** closureEC.scopeChain = closureEC.VO + closure.[[Scope]]
= closureEC.VO + giveMeClosureEC.scopeChain
= closureEC.VO + giveMeClosureEC.VO + giveMeClosure.[[Scope]]
= closureEC.VO + giveMeClosureEC.VO + globalEC.AO
= [closureEC.VO, giveMeClosureEC.VO, globalEC.AO] 其中,最核心的一句话:一个函数定义时就初始化其 [[Scope]] 属性为定义所处的作用域链,当它之后被调用时,会创建新的执行上下文,其中执行上文的作用域链就是:当前执行上下文的活动对象 + 函数的 [[Scope]] 属性。 从时间上,EC 中的作用域链是由函数定义和执行两个阶段构建的。 从空间上,EC 中的作用域链是由 funcEC.AO 和 func.[[Scope]] 两个部分构成的。 由于作用域链最核心的变化部分是 func.[[Scope]],而不是 funcEC.AO。所以可以认为:作用域链是在函数定义时就已经明确,这就是所谓的静态作用域(或词法作用域)。 所以,你最后所说的:
是可以这么理解的。这也解释了:无论闭包在哪里调用,它都能访问其定义时的自由变量(此处为 感谢你耐心的阅读,如有问题,欢迎继续提问。 另外,如果你想更深入地了解,我非常推荐你阅读 Dmitry Soshnikov ECMA-262-3 in detail 系列文章,我觉得讲得非常的精彩。 |
很感謝你這麼快速且用心的回覆,我大致上理解了! 你推薦的那個系列我之前在研究 call by value 以及 call by reference 的問題時有看過,你沒提醒我都忘記有那個系列了哈哈,我會再找時間去看看那系列的。 再次感謝樓主的回覆。 |
您好,首先先感謝你的詳細解釋,我覺得 JS 作用域這篇的思路特別好,透過 JS 引擎在執行時候的觀點可以把一些知識點講解的很清楚,例如說作用域跟變量提升。
然而我這邊有一個小問題,文章裡面說到:
每当 JS 引擎发现一个函数调用 (注意是调用,而不是声明),它就会创建一个新的函数执行环境。
,我想問一下如果是這樣的話,該如何解釋閉包?例如說以下代碼:
在最後一行的
func()
之前都沒有調用裡面的closure
,可是這時候因為已經離開了giveMeClosure
,它的執行環境已經被銷毀,這樣就沒辦法解釋閉包如何存取到 giveMeClosure 執行環境的活動變量。想請問這一個部分應該如何解釋,是不是其實在聲明函數的時候就已經有創建作用域鏈了?或是有其他機制可以解釋這個行為?
感謝
The text was updated successfully, but these errors were encountered: