摘要:下面,讓我們以一個(gè)函數(shù)的創(chuàng)建和激活兩個(gè)時(shí)期來講解作用域鏈?zhǔn)侨绾蝿?chuàng)建和變化的。這時(shí)候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。
前言JavaScript深入系列第五篇,講述作用鏈的創(chuàng)建過程,最后結(jié)合著變量對(duì)象,執(zhí)行上下文棧,讓我們一起捋一捋函數(shù)創(chuàng)建和執(zhí)行的過程中到底發(fā)生了什么?
在《JavaScript深入之執(zhí)行上下文棧》中講到,當(dāng)JavaScript代碼執(zhí)行一段可執(zhí)行代碼(executable code)時(shí),會(huì)創(chuàng)建對(duì)應(yīng)的執(zhí)行上下文(execution context)。
對(duì)于每個(gè)執(zhí)行上下文,都有三個(gè)重要屬性:
變量對(duì)象(Variable object,VO)
作用域鏈(Scope chain)
this
今天重點(diǎn)講講作用域鏈。
作用域鏈在《JavaScript深入之變量對(duì)象》中講到,當(dāng)查找變量的時(shí)候,會(huì)先從當(dāng)前上下文的變量對(duì)象中查找,如果沒有找到,就會(huì)從父級(jí)(詞法層面上的父級(jí))執(zhí)行上下文的變量對(duì)象中查找,一直找到全局上下文的變量對(duì)象,也就是全局對(duì)象。這樣由多個(gè)執(zhí)行上下文的變量對(duì)象構(gòu)成的鏈表就叫做作用域鏈。
下面,讓我們以一個(gè)函數(shù)的創(chuàng)建和激活兩個(gè)時(shí)期來講解作用域鏈?zhǔn)侨绾蝿?chuàng)建和變化的。
函數(shù)創(chuàng)建在《JavaScript深入之詞法作用域和動(dòng)態(tài)作用域》中講到,函數(shù)的作用域在函數(shù)定義的時(shí)候就決定了。
這是因?yàn)楹瘮?shù)有一個(gè)內(nèi)部屬性 [[scope]],當(dāng)函數(shù)創(chuàng)建的時(shí)候,就會(huì)保存所有父變量對(duì)象到其中,你可以理解 [[scope]] 就是所有父變量對(duì)象的層級(jí)鏈,但是注意:[[scope]] 并不代表完整的作用域鏈!
舉個(gè)例子:
function foo() { function bar() { ... } }
函數(shù)創(chuàng)建時(shí),各自的[[scope]]為:
foo.[[scope]] = [ globalContext.VO ]; bar.[[scope]] = [ fooContext.AO, globalContext.VO ];函數(shù)激活
當(dāng)函數(shù)激活時(shí),進(jìn)入函數(shù)上下文,創(chuàng)建 VO/AO 后,就會(huì)將活動(dòng)對(duì)象添加到作用鏈的前端。
這時(shí)候執(zhí)行上下文的作用域鏈,我們命名為 Scope:
Scope = [AO].concat([[Scope]]);
至此,作用域鏈創(chuàng)建完畢。
捋一捋以下面的例子為例,結(jié)合著之前講的變量對(duì)象和執(zhí)行上下文棧,我們來總結(jié)一下函數(shù)執(zhí)行上下文中作用域鏈和變量對(duì)象的創(chuàng)建過程:
var scope = "global scope"; function checkscope(){ var scope2 = "local scope"; return scope2; } checkscope();
執(zhí)行過程如下:
1.checkscope 函數(shù)被創(chuàng)建,保存作用域鏈到 內(nèi)部屬性[[scope]]
checkscope.[[scope]] = [ globalContext.VO ];
2.執(zhí)行 checkscope 函數(shù),創(chuàng)建 checkscope 函數(shù)執(zhí)行上下文,checkscope 函數(shù)執(zhí)行上下文被壓入執(zhí)行上下文棧
ECStack = [ checkscopeContext, globalContext ];
3.checkscope 函數(shù)并不立刻執(zhí)行,開始做準(zhǔn)備工作,第一步:復(fù)制函數(shù)[[scope]]屬性創(chuàng)建作用域鏈
checkscopeContext = { Scope: checkscope.[[scope]], }
4.第二步:用 arguments 創(chuàng)建活動(dòng)對(duì)象,隨后初始化活動(dòng)對(duì)象,加入形參、函數(shù)聲明、變量聲明
checkscopeContext = { AO: { arguments: { length: 0 }, scope2: undefined } }
5.第三步:將活動(dòng)對(duì)象壓入 checkscope 作用域鏈頂端
checkscopeContext = { AO: { arguments: { length: 0 }, scope2: undefined }, Scope: [AO, [[Scope]]] }
6.準(zhǔn)備工作做完,開始執(zhí)行函數(shù),隨著函數(shù)的執(zhí)行,修改 AO 的屬性值
checkscopeContext = { AO: { arguments: { length: 0 }, scope2: "local scope" }, Scope: [AO, [[Scope]]] }
7.查找到 scope2 的值,返回后函數(shù)執(zhí)行完畢,函數(shù)上下文從執(zhí)行上下文棧中彈出
ECStack = [ globalContext ];下一篇文章
《JavaScript深入之從ECMAScript規(guī)范解讀this》
本文相關(guān)鏈接《JavaScript深入之詞法作用域和動(dòng)態(tài)作用域》
《JavaScript深入之執(zhí)行上下文棧》
《JavaScript深入之變量對(duì)象》
深入系列JavaScript深入系列目錄地址:https://github.com/mqyqingfeng/Blog。
JavaScript深入系列預(yù)計(jì)寫十五篇左右,旨在幫大家捋順JavaScript底層知識(shí),重點(diǎn)講解如原型、作用域、執(zhí)行上下文、變量對(duì)象、this、閉包、按值傳遞、call、apply、bind、new、繼承等難點(diǎn)概念。
如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑?qǐng)務(wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎star,對(duì)作者也是一種鼓勵(lì)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/82428.html
摘要:深入系列第七篇,結(jié)合之前所講的四篇文章,以權(quán)威指南的為例,具體講解當(dāng)函數(shù)執(zhí)行的時(shí)候,執(zhí)行上下文棧變量對(duì)象作用域鏈?zhǔn)侨绾巫兓摹G把栽谏钊胫畧?zhí)行上下文棧中講到,當(dāng)代碼執(zhí)行一段可執(zhí)行代碼時(shí),會(huì)創(chuàng)建對(duì)應(yīng)的執(zhí)行上下文。 JavaScript深入系列第七篇,結(jié)合之前所講的四篇文章,以權(quán)威指南的demo為例,具體講解當(dāng)函數(shù)執(zhí)行的時(shí)候,執(zhí)行上下文棧、變量對(duì)象、作用域鏈?zhǔn)侨绾巫兓摹?前言 在《Jav...
摘要:開篇作用域是每種計(jì)算機(jī)語言最重要的基礎(chǔ)之一,因此要想深入的學(xué)習(xí)作用域和作用域鏈就是個(gè)繞不開的話題。這樣由多個(gè)執(zhí)行上下文的變量對(duì)象構(gòu)成的鏈表就叫做作用域鏈。這時(shí)候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。 開篇 作用域是每種計(jì)算機(jī)語言最重要的基礎(chǔ)之一,因此要想深入的學(xué)習(xí)JavaScript,作用域和作用域鏈就是個(gè)繞不開的話題。 在《深入學(xué)習(xí)js之—-執(zhí)行上下文棧》中我們提到...
摘要:使用上一篇文章的例子來說明下自由變量進(jìn)階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第7天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)...
摘要:閉包面試題解由于作用域鏈機(jī)制的影響,閉包只能取得內(nèi)部函數(shù)的最后一個(gè)值,這引起的一個(gè)副作用就是如果內(nèi)部函數(shù)在一個(gè)循環(huán)中,那么變量的值始終為最后一個(gè)值。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第8天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了...
摘要:深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對(duì)閉包的定義為閉包是指那些能夠訪問自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對(duì)閉包的定義為: 閉包是指那些能夠訪問自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...
閱讀 1727·2021-11-22 15:33
閱讀 2107·2021-10-08 10:04
閱讀 3557·2021-08-27 13:12
閱讀 3429·2019-08-30 13:06
閱讀 1478·2019-08-29 16:43
閱讀 1401·2019-08-29 16:40
閱讀 795·2019-08-29 16:15
閱讀 2755·2019-08-29 14:13