摘要:深入系列第四篇,具體講解執(zhí)行上下文中的變量對(duì)象與活動(dòng)對(duì)象。下一篇文章深入之作用域鏈本文相關(guān)鏈接深入之執(zhí)行上下文棧深入系列深入系列目錄地址。
前言JavaScript深入系列第四篇,具體講解執(zhí)行上下文中的變量對(duì)象與活動(dòng)對(duì)象。全局上下文下的變量對(duì)象是什么?函數(shù)上下文下的活動(dòng)對(duì)象是如何分析和執(zhí)行的?還有兩個(gè)思考題幫你加深印象,快來看看吧!
在上篇《JavaScript深入之執(zhí)行上下文?!分兄v到,當(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)講講創(chuàng)建變量對(duì)象的過程。
變量對(duì)象變量對(duì)象是與執(zhí)行上下文相關(guān)的數(shù)據(jù)作用域,存儲(chǔ)了在上下文中定義的變量和函數(shù)聲明。
因?yàn)椴煌瑘?zhí)行上下文下的變量對(duì)象稍有不同,所以我們來聊聊全局上下文下的變量對(duì)象和函數(shù)上下文下的變量對(duì)象。
全局上下文我們先了解一個(gè)概念,叫全局對(duì)象。在 W3C school 中也有介紹:
全局對(duì)象是預(yù)定義的對(duì)象,作為 JavaScript 的全局函數(shù)和全局屬性的占位符。通過使用全局對(duì)象,可以訪問所有其他所有預(yù)定義的對(duì)象、函數(shù)和屬性。
在頂層 JavaScript 代碼中,可以用關(guān)鍵字 this 引用全局對(duì)象。因?yàn)槿謱?duì)象是作用域鏈的頭,這意味著所有非限定性的變量和函數(shù)名都會(huì)作為該對(duì)象的屬性來查詢。
例如,當(dāng)JavaScript 代碼引用 parseInt() 函數(shù)時(shí),它引用的是全局對(duì)象的 parseInt 屬性。全局對(duì)象是作用域鏈的頭,還意味著在頂層 JavaScript 代碼中聲明的所有變量都將成為全局對(duì)象的屬性。
如果看的不是很懂的話,容我再來介紹下全局對(duì)象:
1.可以通過 this 引用,在客戶端 JavaScript 中,全局對(duì)象就是 Window 對(duì)象。
console.log(this);
2.全局對(duì)象是由 Object 構(gòu)造函數(shù)實(shí)例化的一個(gè)對(duì)象。
console.log(this instanceof Object);
3.預(yù)定義了一堆,嗯,一大堆函數(shù)和屬性。
// 都能生效 console.log(Math.random()); console.log(this.Math.random());
4.作為全局變量的宿主。
var a = 1; console.log(this.a);
5.客戶端 JavaScript 中,全局對(duì)象有 window 屬性指向自身。
var a = 1; console.log(window.a); this.window.b = 2; console.log(this.b);
花了一個(gè)大篇幅介紹全局對(duì)象,其實(shí)就想說:
全局上下文中的變量對(duì)象就是全局對(duì)象吶!
函數(shù)上下文在函數(shù)上下文中,我們用活動(dòng)對(duì)象(activation object, AO)來表示變量對(duì)象。
活動(dòng)對(duì)象和變量對(duì)象其實(shí)是一個(gè)東西,只是變量對(duì)象是規(guī)范上的或者說是引擎實(shí)現(xiàn)上的,不可在 JavaScript 環(huán)境中訪問,只有到當(dāng)進(jìn)入一個(gè)執(zhí)行上下文中,這個(gè)執(zhí)行上下文的變量對(duì)象才會(huì)被激活,所以才叫 activation object 吶,而只有被激活的變量對(duì)象,也就是活動(dòng)對(duì)象上的各種屬性才能被訪問。
活動(dòng)對(duì)象是在進(jìn)入函數(shù)上下文時(shí)刻被創(chuàng)建的,它通過函數(shù)的 arguments 屬性初始化。arguments 屬性值是 Arguments 對(duì)象。
執(zhí)行過程執(zhí)行上下文的代碼會(huì)分成兩個(gè)階段進(jìn)行處理:分析和執(zhí)行,我們也可以叫做:
進(jìn)入執(zhí)行上下文
代碼執(zhí)行
進(jìn)入執(zhí)行上下文當(dāng)進(jìn)入執(zhí)行上下文時(shí),這時(shí)候還沒有執(zhí)行代碼,
變量對(duì)象會(huì)包括:
函數(shù)的所有形參 (如果是函數(shù)上下文)
由名稱和對(duì)應(yīng)值組成的一個(gè)變量對(duì)象的屬性被創(chuàng)建
沒有實(shí)參,屬性值設(shè)為 undefined
函數(shù)聲明
由名稱和對(duì)應(yīng)值(函數(shù)對(duì)象(function-object))組成一個(gè)變量對(duì)象的屬性被創(chuàng)建
如果變量對(duì)象已經(jīng)存在相同名稱的屬性,則完全替換這個(gè)屬性
變量聲明
由名稱和對(duì)應(yīng)值(undefined)組成一個(gè)變量對(duì)象的屬性被創(chuàng)建;
如果變量名稱跟已經(jīng)聲明的形式參數(shù)或函數(shù)相同,則變量聲明不會(huì)干擾已經(jīng)存在的這類屬性
舉個(gè)例子:
function foo(a) { var b = 2; function c() {} var d = function() {}; b = 3; } foo(1);
在進(jìn)入執(zhí)行上下文后,這時(shí)候的 AO 是:
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: undefined, c: reference to function c(){}, d: undefined }代碼執(zhí)行
在代碼執(zhí)行階段,會(huì)順序執(zhí)行代碼,根據(jù)代碼,修改變量對(duì)象的值
還是上面的例子,當(dāng)代碼執(zhí)行完后,這時(shí)候的 AO 是:
AO = { arguments: { 0: 1, length: 1 }, a: 1, b: 3, c: reference to function c(){}, d: reference to FunctionExpression "d" }
到這里變量對(duì)象的創(chuàng)建過程就介紹完了,讓我們簡潔的總結(jié)我們上述所說:
全局上下文的變量對(duì)象初始化是全局對(duì)象
函數(shù)上下文的變量對(duì)象初始化只包括 Arguments 對(duì)象
在進(jìn)入執(zhí)行上下文時(shí)會(huì)給變量對(duì)象添加形參、函數(shù)聲明、變量聲明等初始的屬性值
在代碼執(zhí)行階段,會(huì)再次修改變量對(duì)象的屬性值
思考題最后讓我們看幾個(gè)例子:
1.第一題
function foo() { console.log(a); a = 1; } foo(); // ??? function bar() { a = 1; console.log(a); } bar(); // ???
第一段會(huì)報(bào)錯(cuò):Uncaught ReferenceError: a is not defined。
第二段會(huì)打?。?b>1。
這是因?yàn)楹瘮?shù)中的 "a" 并沒有通過 var 關(guān)鍵字聲明,所有不會(huì)被存放在 AO 中。
第一段執(zhí)行 console 的時(shí)候, AO 的值是:
AO = { arguments: { length: 0 } }
沒有 a 的值,然后就會(huì)到全局去找,全局也沒有,所以會(huì)報(bào)錯(cuò)。
當(dāng)?shù)诙螆?zhí)行 console 的時(shí)候,全局對(duì)象已經(jīng)被賦予了 a 屬性,這時(shí)候就可以從全局找到 a 的值,所以會(huì)打印 1。
2.第二題
console.log(foo); function foo(){ console.log("foo"); } var foo = 1;
會(huì)打印函數(shù),而不是 undefined 。
這是因?yàn)樵谶M(jìn)入執(zhí)行上下文時(shí),首先會(huì)處理函數(shù)聲明,其次會(huì)處理變量聲明,如果如果變量名稱跟已經(jīng)聲明的形式參數(shù)或函數(shù)相同,則變量聲明不會(huì)干擾已經(jīng)存在的這類屬性。
下一篇文章《JavaScript深入之作用域鏈》
本文相關(guān)鏈接《JavaScript深入之執(zhí)行上下文?!?/p> 深入系列
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://www.ezyhdfw.cn/yun/88230.html
摘要:下面,讓我們以一個(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í)行上下文?!分兄v到,當(dāng)JavaScript代碼執(zhí)行一段可執(zhí)行代...
摘要:深入系列第七篇,結(jié)合之前所講的四篇文章,以權(quán)威指南的為例,具體講解當(dāng)函數(shù)執(zhí)行的時(shí)候,執(zhí)行上下文棧變量對(duì)象作用域鏈?zhǔn)侨绾巫兓?。前言在深入之?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ì)劃一共期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)劃,點(diǎn)擊查看前端進(jìn)階的破冰之旅本期推薦文章深入之執(zhí)行上下文棧和深入之變量對(duì)象,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,今天是第二天。 本計(jì)劃一共28期,每期...
摘要:深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對(duì)閉包的定義為閉包是指那些能夠訪問自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對(duì)閉包的定義為: 閉包是指那些能夠訪問自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...
摘要:閉包面試題解由于作用域鏈機(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),如果你還不了...
閱讀 3437·2021-11-22 09:34
閱讀 2992·2021-10-09 09:43
閱讀 1526·2021-09-24 09:47
閱讀 2262·2019-08-30 12:53
閱讀 1064·2019-08-29 14:00
閱讀 3496·2019-08-29 13:17
閱讀 2338·2019-08-28 18:00
閱讀 1353·2019-08-26 12:00