javascript:作用域鏈淺析

前言

為可以大概了解作用域鏈?zhǔn)莻€什么東西,本文著重說明作用域鏈,盡量不引入其他的概念。

變量對象

在說作用域鏈前,先簡單地說明變量對象,畢竟是作用域鏈的核心組成。每個函數(shù)內(nèi)部都會定義變量,會定義函數(shù),在全局環(huán)境下也會定義函數(shù)、變量。對應(yīng)的區(qū)域都會有一個特殊對象,這個對象就會存放對應(yīng)區(qū)域的變量、函數(shù),這個特殊的對象就是變量對象。所以說全局環(huán)境有和全局環(huán)境對應(yīng)的變量對象,每個函數(shù)內(nèi)部也有一個與之對應(yīng)的變量對象,不如下面的代碼:

<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)境的變量對象存儲的是:a, b, fn
  • fn函數(shù)的變量對象存儲的是:isShow,gihubLink;你可以看見,fn函數(shù)的變量對象沒有包含全局環(huán)境定義的變量和函數(shù)
作用域鏈

為什么要說變量對象呢?因為作用域鏈就是由變量對象組成,作用域鏈?zhǔn)且粋€由變量對象組成的列表,一個有序,只能由頭開始逐個往尾訪問的列表(說是列表其實更應(yīng)該說是鏈表,先不要在意這個概念)。
并且作用域鏈和變量對象有一個共同的特點:每個區(qū)域都會有一個與之對象對的。比如說上面的代碼中,全局環(huán)境有一個與之對應(yīng)的變量對象,也有一個和全局環(huán)境對應(yīng)的作用域鏈;fn函數(shù)也是如此。

那么作用域鏈?zhǔn)怯心男┳兞繉ο蠼M成呢?

我們先看下圖:



由上圖應(yīng)該可以看出,作用域鏈由當(dāng)前區(qū)域的變量對象作為開頭,然后是逐層往外直至全局環(huán)境的變量對象組成如上圖一樣的列表,這就是作用域鏈,并且如上文所說,每個區(qū)域都有這樣一個與之對應(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)該有這樣的體驗,在函數(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)境)的變量,為什么可以,就是因為fn函數(shù)的作用域鏈,在變量調(diào)用的時候(在fn就是訪問c變量的時候),會在當(dāng)前作用域鏈的頭部開始往尾部,依次在變量對象中查詢對應(yīng)的變量,找到即返回,不再繼續(xù)查詢,這個也是內(nèi)層同名變量比外層同名變量優(yōu)先級更高的原因,這個查詢的過程叫做變量解析,也叫標(biāo)識符解析,console.log(c);會拋出異常就是因為全局環(huán)境的作用域鏈中的變量對象沒有該變量。

結(jié)語

正如本文開頭所說,本文僅是淺析作用域鏈,一些相關(guān)概念都被隱掉了,比如說上文說的“區(qū)域“,應(yīng)該說是作用域或執(zhí)行環(huán)境,這兩個概念其實說的不是很明確,比如說執(zhí)行環(huán)境,在《javascript高級程序設(shè)計》的4.2中有說到,簡直堪稱極具迷惑性,標(biāo)題更加是醉”執(zhí)行環(huán)境和作用域“,然而基本沒有談到作用域。作用域在《javascript權(quán)威指南》的3.10中倒是說的挺多,還分變量作用域和函數(shù)作用域。不過啊,要是拘泥于這些細(xì)節(jié)更加難搞明白作用域鏈了。上文也說道作用域鏈更像鏈表,個人也是這樣認(rèn)為,但兩書中都沒有明確地說是,權(quán)威指南倒是提了一下,而且作用域鏈也是很符合鏈表的特點,如果不了解鏈表,但由不了解其他語言,推薦這本書《數(shù)據(jù)結(jié)構(gòu)與算法JavaScript描述》,吐槽完畢,作用域鏈的解析當(dāng)然沒有那么淺顯,想了解更多細(xì)節(jié)還是自己去看看書。

有說得不對的,歡迎指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容