javascript精雕細(xì)琢(三):作用域與作用域鏈

引言

???????作用域與作用域鏈?zhǔn)荍S應(yīng)用中無時無刻不在影響程序運(yùn)行的關(guān)鍵屬性,但是由于它的不可見性,或者說它存在的過于普遍粥鞋,簡直就像空氣一樣。所以對它的談及瞄崇,都很簡單呻粹,而理解起來也不復(fù)雜。


???????但是由于它的重要性苏研,對它做一個篇幅的說明等浊,也是一件理所應(yīng)當(dāng)?shù)氖虑椤6宜鋵?shí)也并沒有理解上那么簡單楣富。


???????本文對作用域及作用域鏈的說明凿掂,可能并不全面。筆者盡量以自身開發(fā)過程中的理解,做到表述全面庄萎。

1踪少、執(zhí)行環(huán)境

???????按照《JavaScript高級程序設(shè)計》第3版中的定義——執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問其他數(shù)據(jù),決定了它們各自的行為糠涛。每個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的變量對象援奢,環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中。

???????對于環(huán)境的簡單理解忍捡,可以理解為{}一個大括號就是一個執(zhí)行環(huán)境集漾。如{{}},就是包含關(guān)系的兩個執(zhí)行環(huán)境砸脊。而由于所有的函數(shù)和變量具篇,最終都是通過最外圍有對應(yīng)的調(diào)用,才能最終實(shí)現(xiàn)運(yùn)行凌埂,所以將最外圍的執(zhí)行環(huán)境定義為全局執(zhí)行環(huán)境驱显,在宿主為web瀏覽器時,全局執(zhí)行環(huán)境就為window對象瞳抓。

???????每個函數(shù)都有自己的執(zhí)行環(huán)境埃疫。當(dāng)執(zhí)行程序進(jìn)入一個函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中孩哑。而在函數(shù)執(zhí)行之后栓霜,棧將環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境横蜒。之后胳蛮,該環(huán)境因?yàn)?strong>執(zhí)行完畢,隨即被銷毀愁铺。但有一個例外鹰霍,全局環(huán)境將永遠(yuǎn)不會被銷毀,直到程序被關(guān)閉茵乱,如關(guān)閉瀏覽器。

image

由上圖我們清晰的看到JavaScript的兩個階段的執(zhí)行流程孟岛。

2瓶竭、作用域與作用域鏈

???????作用域鏈和作用域是一個包含關(guān)系。當(dāng)代碼在一個環(huán)境中執(zhí)行時渠羞,會創(chuàng)建變量對象的一個作用域鏈斤贰。而作用域鏈中,包含的就是一個個有序排列的作用域次询。作用域鏈的作用荧恍,就是保證執(zhí)行環(huán)境中的變量和函數(shù)的有序訪問

???????每次的變量或函數(shù)聲明,都會形成一個標(biāo)識符(即變量名或函數(shù)名)送巡。 作用域鏈中的向上查找摹菠,實(shí)際上就是標(biāo)識符的查找。找到匹配的標(biāo)識符骗爆,就調(diào)用它的值次氨。

???????作用域鏈中包含的每個作用域?qū)ο螅渲卸及陨憝h(huán)境中可訪問的變量或函數(shù)(script作用域中摘投,為全部的變量和函數(shù);函數(shù)作用域中煮寡,子函數(shù)調(diào)用父函數(shù)環(huán)境中的變量或函數(shù)會形成閉包,那么可訪問變量就為閉包調(diào)用的變量)犀呼。換一種角度理解的話幸撕,這些環(huán)境中可訪問的變量或函數(shù)就是標(biāo)識符,是當(dāng)前作用域中可通過作用域鏈向上查找的標(biāo)識符外臂。

???????一大段的文字不光讀起來枯燥杈帐,理解起來也困難。所以专钉,stop talking挑童,show code。


以函數(shù)為例

function test() {
    let a = 1; //注釋此行跃须,保留其他a站叼,c()打印2,并且作用域鏈?zhǔn)ラ]包對象
    let b = 0;
    
    return () => { //形成閉包環(huán)境
        console.log(a);
        }
    }

    let a = 2; //注釋此行及test中的a菇民,c()打印3
    window.a = 3;  //注釋全部a尽楔,報錯

    const c = test();
    c();

    console.dir(test);
    console.dir(c);
        



以上代碼,通過3次注釋以及chrome瀏覽器打印第练,可以清晰的看到作用域與作用域鏈的形成及作用域鏈按順序查找的特性

1)首先是閉包調(diào)用——所有a都不注釋

image


由上圖可以看出阔馋,此時作用域鏈中存在3個作用域?qū)ο蟆?/strong> 按索引順序?yàn)?strong>0—Closure閉包環(huán)境、1—Script標(biāo)簽環(huán)境娇掏、2—Global全局環(huán)境;

索引順序就是標(biāo)識符的查找順序呕寝,所以當(dāng)執(zhí)行函數(shù)c()時,先在Closure閉包環(huán)境中查找婴梧,然后是Script標(biāo)簽作用域下梢,最后是Global全局作用域。因?yàn)樾纬闪碎]包塞蹭,那么標(biāo)識符的查找肯定能在閉包環(huán)境中找到對應(yīng)結(jié)果孽江,所以打印1;

值得注意的一點(diǎn)是,Closure與Script作用域?qū)ο笾蟹纾鎯Φ臉?biāo)識符的不同岗屏。closure只存儲調(diào)用值a = 1,并沒有存儲b = 0。而Script中將環(huán)境中的所有標(biāo)識符都存在了對象中;


2)然后是取消閉包調(diào)用这刷,改為Script標(biāo)簽作用域查找——注釋test中的a = 1

image


由上圖可以看出婉烟,此時作用域鏈中的Closure閉包作用域消失,只剩下2個對象0—Script標(biāo)簽環(huán)境崭歧、2—Global全局環(huán)境;

那么同樣按索引順序查找隅很,找到了Script標(biāo)簽環(huán)境中的a = 2,沒有繼續(xù)尋找Global全局環(huán)境中的window.a = 3率碾,最終打印2;


3)最后是Global全局作用域查找——注釋test中的a = 1及script中的a = 2

image


與2)中情況對比叔营,作用域鏈中的對象沒有改變所宰。但是Script對象中的標(biāo)識符绒尊,隨著a = 2被注釋而消失

按索引順序查找,找到了Script標(biāo)簽環(huán)境中沒有a仔粥,繼續(xù)尋找Global全局環(huán)境婴谱,最終找到window.a = 3,打印3;



函數(shù)test的打印躯泰,從始至終都是Script標(biāo)簽作用域及Global全局作用域谭羔。理解了c函數(shù)的作用域鏈,自然就明白了函數(shù)test的麦向,所以不再展開贅述瘟裸。


如有錯誤或闡述不充分之處,歡迎指正~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诵竭,一起剝皮案震驚了整個濱河市话告,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卵慰,老刑警劉巖沙郭,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異裳朋,居然都是意外死亡病线,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門再扭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氧苍,“玉大人,你說我怎么就攤上這事泛范。” “怎么了紊撕?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵罢荡,是天一觀的道長。 經(jīng)常有香客問我,道長区赵,這世上最難降的妖魔是什么惭缰? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮笼才,結(jié)果婚禮上漱受,老公的妹妹穿的比我還像新娘。我一直安慰自己骡送,他們只是感情好昂羡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摔踱,像睡著了一般虐先。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上派敷,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天蛹批,我揣著相機(jī)與錄音,去河邊找鬼篮愉。 笑死腐芍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的试躏。 我是一名探鬼主播猪勇,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冗酿!你這毒婦竟也來了埠对?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤裁替,失蹤者是張志新(化名)和其女友劉穎项玛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弱判,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡襟沮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了昌腰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片开伏。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖遭商,靈堂內(nèi)的尸體忽然破棺而出固灵,到底是詐尸還是另有隱情,我是刑警寧澤劫流,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布巫玻,位于F島的核電站丛忆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏仍秤。R本人自食惡果不足惜熄诡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诗力。 院中可真熱鬧凰浮,春花似錦、人聲如沸苇本。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圈澈。三九已至惫周,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間康栈,已是汗流浹背递递。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啥么,地道東北人登舞。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像悬荣,于是被迫代替她去往敵國和親菠秒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容