前言
為可以大概了解作用域鏈?zhǔn)莻€(gè)什么東西,本文著重說明作用域鏈秀菱,盡量不引入其他的概念柿菩。
變量對(duì)象
在說作用域鏈前戚嗅,先簡(jiǎn)單地說明變量對(duì)象,畢竟是作用域鏈的核心組成枢舶。每個(gè)函數(shù)內(nèi)部都會(huì)定義變量懦胞,會(huì)定義函數(shù),在全局環(huán)境下也會(huì)定義函數(shù)凉泄、變量躏尉。對(duì)應(yīng)的區(qū)域都會(huì)有一個(gè)特殊對(duì)象,這個(gè)對(duì)象就會(huì)存放對(duì)應(yīng)區(qū)域的變量后众、函數(shù)胀糜,這個(gè)特殊的對(duì)象就是變量對(duì)象。所以說全局環(huán)境有和全局環(huán)境對(duì)應(yīng)的變量對(duì)象蒂誉,每個(gè)函數(shù)內(nèi)部也有一個(gè)與之對(duì)應(yīng)的變量對(duì)象教藻,不如下面的代碼:
<script>
var a = 1;
var b = [1, 2, 3, 4, 5];
function fn(isShow){
var gihubLink = 'https://github.com/issaxite';
if(isShow) {
console.log(githubLink);
} else {
console.log('issax');
}
}
</script>
上面的代碼中,
- 全局環(huán)境的變量對(duì)象存儲(chǔ)的是:a, b, fn
- fn函數(shù)的變量對(duì)象存儲(chǔ)的是:isShow,gihubLink右锨;你可以看見括堤,fn函數(shù)的變量對(duì)象沒有包含全局環(huán)境定義的變量和函數(shù)
作用域鏈
為什么要說變量對(duì)象呢?因?yàn)樽饔糜蜴溇褪怯勺兞繉?duì)象組成绍移,作用域鏈?zhǔn)且粋€(gè)由變量對(duì)象組成的列表悄窃,一個(gè)有序,只能由頭開始逐個(gè)往尾訪問的列表(說是列表其實(shí)更應(yīng)該說是鏈表蹂窖,先不要在意這個(gè)概念)轧抗。
并且作用域鏈和變量對(duì)象有一個(gè)共同的特點(diǎn):每個(gè)區(qū)域都會(huì)有一個(gè)與之對(duì)象對(duì)的。比如說上面的代碼中恼策,全局環(huán)境有一個(gè)與之對(duì)應(yīng)的變量對(duì)象鸦致,也有一個(gè)和全局環(huán)境對(duì)應(yīng)的作用域鏈潮剪;fn函數(shù)也是如此。
那么作用域鏈?zhǔn)怯心男┳兞繉?duì)象組成呢分唾?
我們先看下圖:
由上圖應(yīng)該可以看出抗碰,作用域鏈由當(dāng)前區(qū)域的變量對(duì)象作為開頭,然后是逐層往外直至全局環(huán)境的變量對(duì)象組成如上圖一樣的列表绽乔,這就是作用域鏈弧蝇,并且如上文所說,每個(gè)區(qū)域都有這樣一個(gè)與之對(duì)應(yīng)的作用域鏈折砸。比如下面的代碼:
<script>
var a = 1;
var b = [1, 2, 3, 4, 5];
function fn(isShow){
var gihubLink = 'https://github.com/issaxite';
function fn1(param1, param2){
var mailLink = 'issaxite@gmail.com';
}
}
</script>
-
fn1函數(shù)的作用域鏈:
-
fn的作用域鏈:
-
全局環(huán)境的作用域鏈
那么作用域鏈的作用是什么看疗?
jser都應(yīng)該有這樣的體驗(yàn),在函數(shù)內(nèi)部可以訪問到外部區(qū)域的變量和函數(shù)睦授,而在外部區(qū)域訪問不了函數(shù)內(nèi)定義的變量:
<script>
var a = 1;
var b = 2;
function fn(){
var c = 3;
console.log(a, b, c)
}
console.log(c);
</script>
如上所示两芳,fn函數(shù)內(nèi)部可以訪問到外層區(qū)域(全局環(huán)境)的變量,為什么可以去枷,就是因?yàn)閒n函數(shù)的作用域鏈怖辆,在變量調(diào)用的時(shí)候(在fn就是訪問c變量的時(shí)候),會(huì)在當(dāng)前作用域鏈的頭部開始往尾部删顶,依次在變量對(duì)象中查詢對(duì)應(yīng)的變量竖螃,找到即返回,不再繼續(xù)查詢逗余,這個(gè)也是內(nèi)層同名變量比外層同名變量?jī)?yōu)先級(jí)更高的原因特咆,這個(gè)查詢的過程叫做變量解析,也叫標(biāo)識(shí)符解析录粱,
console.log(c);
會(huì)拋出異常就是因?yàn)槿汁h(huán)境的作用域鏈中的變量對(duì)象沒有該變量腻格。
結(jié)語
正如本文開頭所說,本文僅是淺析作用域鏈关摇,一些相關(guān)概念都被隱掉了荒叶,比如說上文說的“區(qū)域“,應(yīng)該說是作用域或執(zhí)行環(huán)境输虱,這兩個(gè)概念其實(shí)說的不是很明確些楣,比如說執(zhí)行環(huán)境,在《javascript高級(jí)程序設(shè)計(jì)》的4.2中有說到宪睹,簡(jiǎn)直堪稱極具迷惑性愁茁,標(biāo)題更加是醉”執(zhí)行環(huán)境和作用域“,然而基本沒有談到作用域亭病。作用域在《javascript權(quán)威指南》的3.10中倒是說的挺多鹅很,還分變量作用域和函數(shù)作用域。不過啊罪帖,要是拘泥于這些細(xì)節(jié)更加難搞明白作用域鏈了促煮。上文也說道作用域鏈更像鏈表邮屁,個(gè)人也是這樣認(rèn)為,但兩書中都沒有明確地說是菠齿,權(quán)威指南倒是提了一下佑吝,而且作用域鏈也是很符合鏈表的特點(diǎn),如果不了解鏈表绳匀,但由不了解其他語言芋忿,推薦這本書《數(shù)據(jù)結(jié)構(gòu)與算法JavaScript描述》,吐槽完畢疾棵,作用域鏈的解析當(dāng)然沒有那么淺顯戈钢,想了解更多細(xì)節(jié)還是自己去看看書。
有說得不對(duì)的是尔,歡迎指出