JavaScript之作用域與作用域鏈

點擊此處訪問我的github了解更多詳情

今天是2016的第一天仲义,我們得揚帆起航踏上新的征程了婶熬。此篇闡述JavaScript中很重要的幾個概念:作用域與作用域鏈及相關(guān)知識點剑勾。

我們先從變量與作用域的行為關(guān)系開始討論。

變量作用域

JavaScript中赵颅,變量有全局變量及局部變量之分虽另,而能定義變量作用域的語塊只有函數(shù)。與局部變量有關(guān)的一種有趣特性饺谬,在此處不得不談--變量提升捂刺。

變量提升

變量提升為何物?

JavaScript的變量聲明會被提升到它們所在函數(shù)的頂部募寨,而初始化仍舊在原來的地方叠萍。JavaScript引擎并沒有重寫代碼:每次調(diào)用函數(shù)時,聲明都會重新提升绪商。


    var name = 'Jog'; //全局變量
    function prison() {
        console.log(a); //輸出undefined
        var a = 1;//局部變量
        console.log(a); //輸出1
        console.log(name); //輸出Jog
    }
    prison();
    
    var name = 'Jog';
    function prison() {
        console.log(name); //輸出undefined
        var name = 'Hans';
    }
    prison();

此處name的聲明被提升到函數(shù)的頂部辅鲸,變量查找時先從局部作用域開始格郁,未找到則由內(nèi)而外最后到全局作用域。

接下來我們詳細(xì)分析一下JavaScript的提升方式独悴。

變量提升與執(zhí)行環(huán)境對象

學(xué)習(xí)任何一門語言例书,都像學(xué)習(xí)魔術(shù)一樣,初時引人迷惑刻炒,驚嘆决采;然而當(dāng)秘密被揭開時幾乎令人失望,JavaScript不外如是坟奥。

    1. 提升

執(zhí)行某代碼塊時树瞭,JavaScript引擎先解釋,再運行爱谁。解釋過程主要幾個過程:

- (1) 聲明該作用域內(nèi)var變量
- (2) 聲明并初始化函數(shù)參數(shù)
- (3) 聲明并初始化聲明式函數(shù)

詳細(xì)可查看本系列筆記JavaScript之解釋與執(zhí)行機制

    1. 執(zhí)行環(huán)境與執(zhí)行環(huán)境對象

執(zhí)行環(huán)境(execution context)是一種概念晒喷,每當(dāng)函數(shù)被調(diào)用都會產(chǎn)生一個新的執(zhí)行環(huán)境。

執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù)访敌,決定了它們各自的行為凉敲。

- 1. 每個函數(shù)都有自己的執(zhí)行環(huán)境。  當(dāng)執(zhí)行流進入一個函數(shù)時寺旺,執(zhí)行環(huán)境就被推入一個環(huán)境棧中爷抓;函數(shù)執(zhí)行之后,棧將其執(zhí)行環(huán)境彈出阻塑,控制權(quán)返回到之前的執(zhí)行環(huán)境蓝撇。
- 2. 如果變量在當(dāng)前執(zhí)行環(huán)境內(nèi)可訪問,則該變量在當(dāng)前作用域內(nèi)叮姑。
- 3. JavaScript訪問變量唉地,其實就是訪問該執(zhí)行環(huán)境對象(變量對象)中的屬性据悔。
- 4. 全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境。

執(zhí)行環(huán)境對象--每個執(zhí)行環(huán)境都有一個與之對應(yīng)的變量對象耘沼,執(zhí)行環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中极颓。


    function fn(arg) {
        var name = 'Far';
        inner();
        function inner() {
            console.log('inner');
        }
    }
    fn('test');

在調(diào)用fn時,其過程如下

- 1. 創(chuàng)建一個空執(zhí)行環(huán)境對象群嗤;
- 2. 聲明參數(shù)并賦值菠隆;{arg: 1}
- 3. 聲明局部變量;{arg:1, name: undefined}
- 4. 預(yù)定義聲明式函數(shù)狂秘;{arg:1, name: undefined骇径, inner: function(){console.log('inner');}}
- 5. 代碼執(zhí)行時,局部變量被賦值者春;{...name: 'Far'...}
- 6. 執(zhí)行環(huán)境對象上變量和函數(shù)屬性保持不變破衔,調(diào)用inner函數(shù)時,其內(nèi)部會創(chuàng)建一個新的執(zhí)行環(huán)境對象钱烟,依此可遞歸形成一條作用域鏈晰筛。

作用域與作用域鏈

當(dāng)一個變量在某執(zhí)行回家內(nèi)可以被訪問,我們稱該變量在當(dāng)前作用域內(nèi)拴袭。

代碼某一執(zhí)行環(huán)境中執(zhí)行時读第,會創(chuàng)建該執(zhí)行環(huán)境對應(yīng)的變量對象的一個作用域鏈。

JavaScript引擎在執(zhí)行環(huán)境對象中查找作用域內(nèi)的變量或函數(shù)拥刻,其查找順序由內(nèi)而外向上直到全局執(zhí)行環(huán)境對象怜瞒,這個順序就形成作用域鏈

作用域鏈的前端般哼,始終是當(dāng)前執(zhí)行環(huán)境對應(yīng)的變量對象吴汪。若此執(zhí)行環(huán)境是函數(shù),則將其活動對象作為變量對象逝她。作用域鏈中的下一個變量對象來自于當(dāng)前變量對象的包含(外部)執(zhí)行環(huán)境浇坐,如此一直到全局執(zhí)行環(huán)境;全局執(zhí)行環(huán)境的變量對象始終是作用域鏈中的最后一個變量對象黔宛。


    var age = 22;
    var country = 'China';
    var name = 'Java';
    var job = 'Web';
    function outer() {
        console.log(age);  //輸出22
        console.log(country); //輸出undefined
        var country = 'Union';
        var name = 'Python';
        inner();
        function inner() {
            console.log(name); //輸出Python
            console.log(job); //輸出Web
        }
    }
    outer();

代碼輸出結(jié)果如上:

- 1. outer函數(shù)執(zhí)行時近刘,首先在outer執(zhí)行環(huán)境對象中查找age和country變量結(jié)果country存在但并未初始化賦值,輸出undefined;而age未找到于是沿著作用域鏈向上到全局執(zhí)行環(huán)境臀晃,在其變量對象中存在age屬性觉渴,于是輸出其值22.
- 2. inner函數(shù)執(zhí)行時創(chuàng)建自己的執(zhí)行環(huán)境對象,其并沒有定義name和job等變量徽惋,于是沿著作用域鏈向上到達outer函數(shù)的執(zhí)行環(huán)境案淋,在其變量對象中存在name于是輸出其值Python;而未找到j(luò)ob于是繼續(xù)向上直到全局執(zhí)行環(huán)境险绘,找到并輸出其值踢京,結(jié)束誉碴;若依然未找到,則會報錯瓣距,停止運行黔帕。

注:函數(shù)參數(shù)亦被當(dāng)作變量對待,故其訪問規(guī)則與普通變量相同蹈丸。

延長作用域鏈

某些語句可以在作用域鏈的前端臨時增加一個變量對象成黄,該變量對象會在代碼執(zhí)行結(jié)束后移除。常見如:

  • try-catch語句逻杖;
    catch語句會創(chuàng)建一個新變量對象奋岁,包含被拋出的錯誤對象的聲明。
  • with語句荸百;
    with語句會創(chuàng)建一個包含語句接收對象的所有屬性和方法的變量對象闻伶。

    function getAttr(data) {
        var obj = data;
        with(obj) {
            var o = location;
        }
        console.log(o);
    }
    getAttr(window);

上面with語句接收window對象,其創(chuàng)建的變量對象就包含了window對象所有屬性和方法够话,于是可以在其執(zhí)行環(huán)節(jié)直接訪問location變量虾攻,也就是正常的window.location。

強烈建議不要使用with語句更鲁。

本篇筆記闡述JavaScript執(zhí)行環(huán)境與執(zhí)行環(huán)境對象,變量對象奇钞,作用域與作用域鏈澡为,耗時四小時,還有諸多不足之處待日后補充改進景埃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末媒至,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子谷徙,更是在濱河造成了極大的恐慌拒啰,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件完慧,死亡現(xiàn)場離奇詭異谋旦,居然都是意外死亡,警方通過查閱死者的電腦和手機屈尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門册着,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脾歧,你說我怎么就攤上這事甲捏。” “怎么了鞭执?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵司顿,是天一觀的道長芒粹。 經(jīng)常有香客問我,道長大溜,這世上最難降的妖魔是什么化漆? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮猎提,結(jié)果婚禮上慰于,老公的妹妹穿的比我還像新娘。我一直安慰自己磕潮,他們只是感情好梳杏,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伞租,像睡著了一般贞谓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上葵诈,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天裸弦,我揣著相機與錄音,去河邊找鬼作喘。 笑死理疙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泞坦。 我是一名探鬼主播窖贤,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贰锁!你這毒婦竟也來了赃梧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤豌熄,失蹤者是張志新(化名)和其女友劉穎授嘀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锣险,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡蹄皱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了芯肤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夯接。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纷妆,靈堂內(nèi)的尸體忽然破棺而出盔几,到底是詐尸還是另有隱情,我是刑警寧澤掩幢,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布逊拍,位于F島的核電站上鞠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏芯丧。R本人自食惡果不足惜芍阎,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缨恒。 院中可真熱鬧谴咸,春花似錦、人聲如沸骗露。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萧锉。三九已至珊随,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柿隙,已是汗流浹背叶洞。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留禀崖,地道東北人衩辟。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像波附,于是被迫代替她去往敵國和親惭婿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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