【每日一題】說下你對(duì)變量的作用域鏈的理解

人生苦短,總需要一點(diǎn)儀式感。比如學(xué)前端~
全局變量和局部變量
“全局變量”指的是定義在所有函數(shù)之外的變量(也就是定義在全局代碼中的變量)
“局部變量”與之相對(duì),所指的是在某個(gè)函數(shù)中定義的變量。
其中,函數(shù)內(nèi)的代碼可以訪問自己上層函數(shù)的變量,也可以訪問全局變量,這樣就構(gòu)成了作用域鏈。
特殊的:隱式聲明一個(gè)變量(沒有使用 var 等語句就聲明的變量),該變量不管在哪個(gè)作用域里,就會(huì)被默認(rèn)為是全局變量。
作用域鏈
JavaScript 引擎執(zhí)行一段代碼時(shí),會(huì)創(chuàng)建對(duì)應(yīng)的執(zhí)行上下文并推入到執(zhí)行棧中。
查找一個(gè)變量的時(shí)候,會(huì)先從當(dāng)前代碼所在的上下文的環(huán)境記錄中查找,
如果找到,直接返回這個(gè)變量的值;
如果沒有找到,就會(huì)到上一級(jí)執(zhí)行上下文的環(huán)境記錄中查找,找不到會(huì)一直向上,直到全局上下文的環(huán)境記錄。
這樣有多個(gè)執(zhí)行上下文的環(huán)境記錄構(gòu)成的鏈表,就叫做作用域鏈。
當(dāng)前執(zhí)行上下文 - 上一級(jí) - 上上級(jí) - …… - 全局上下文。
作用域鏈包含了執(zhí)行環(huán)境有權(quán)訪問的變量、函數(shù)的有序訪問。它是一個(gè)由變量對(duì)象(VO/AO)組成的單項(xiàng)鏈表,主要用來進(jìn)行變量查找。
js 內(nèi)部有一個(gè)[[scope]]屬性,這個(gè)屬性就是指向作用域鏈的頂端
var val = "全局變量";
function AA(y) {
var val = "局部變量";
function BB() {
var z = 0;
alert(val);
}
BB();
}
AA(5);
簡(jiǎn)單分析上面的流程:
全局執(zhí)行環(huán)境:[[scope]] ---> VO[AA,val],只有全局VO, [[scope]]直接指向VO。
函數(shù) AA 執(zhí)行環(huán)境:[[scope]] ---> VO[y,BB,val, VO[AA,val]],首先全局VO壓入棧底,然后函數(shù)AA VO壓入棧頂,[[scope]] 屬性指向棧頂,變量、函數(shù)搜索就從棧頂開始。
函數(shù) BB 執(zhí)行環(huán)境:[[scope]]---> VO[z, VO[y,BB,val], VO[AA,val]],首先全局 VO 壓入棧底,然后依次 AA、BB 壓入棧,BB 處于棧頂,[[scope]]屬性直接指向 BB 的 VO。
應(yīng)用場(chǎng)景:比如調(diào)用 BB,進(jìn)入 BB 的執(zhí)行環(huán)境,在執(zhí)行 alert 的時(shí)候,首先會(huì)去查找 val 的聲明,會(huì)先在作用域鏈的頂端查找,沒查到就會(huì)沿著作用域鏈繼續(xù)往下查找,直到查找到AA的變量對(duì)象就停止。
總結(jié):
函數(shù)執(zhí)行的時(shí)候,就將當(dāng)前函數(shù)的VO放在鏈表開頭,后面依次是上層函數(shù),最后是全局對(duì)象。變量查找則依次從鏈表的頂端開始。
js有個(gè)內(nèi)部[[scope]],這個(gè)屬性包含了函數(shù)的作用域?qū)ο蟮募希@個(gè)集合就稱為函數(shù)的作用域鏈。它決定了哪些變量或者函數(shù)能在當(dāng)前函數(shù)中被訪問以及它的訪問順序。
VO 和 AO
VO:全局變量對(duì)象(Varibale Object) , 指向全局對(duì)象window,包含定義的全局變量。AO:活動(dòng)變量對(duì)象(Activation Object),其實(shí)也是變量對(duì)象,可以理解為VO在函數(shù)中的叫法。不過他除了包含局部的變量,還包括函數(shù)內(nèi)部的形參、arguments對(duì)象、this對(duì)象等。
區(qū)分作用域與this
變量的作用域區(qū)別于 this指針:變量作用域是靜態(tài)的,在變量聲明后就確定的,也就是說變量聲明在哪里,他的作用域就是哪里(特殊一點(diǎn):沒有用關(guān)鍵詞聲明的是全局);
而 this指針 則是動(dòng)態(tài)的,根據(jù)最后的調(diào)用情況判斷其指向誰,甚至根據(jù)call、apply、bind、new等影響能被手動(dòng)改變。

