JS 做用域(執行環境)與做用鏈---JS 學習筆記(二)

一  做用域(執行環境)javascript

做用域:定義了變量和函數有權訪問的其餘數據,決定了他們各自的行爲。--------《JS高級程序設計》4.2 html

好難理解啊~參考了參考尤克希的博客內容,大致上理解了做用域。 前端

做用域規定了函數和變量的可用的有效的範圍。這樣的好處是,避免了命名衝突;肯定什麼時候銷燬他們,釋放內存。這個做用域中全部的函數和對象,都保存在變量對象裏。每一個做用域都有這樣一個變量對象。可是咱們編寫的代碼是沒法訪問到這個對象的,解析器在處理數據時會在後臺使用它。java

做用域分爲兩類:全局做用域和函數做用域。瀏覽器

全局做用域是最外圍的一個做用域。根據 ECMAScript 實現所在的宿主環境不一樣,表示做用域的對象也不同。在 Web 瀏覽器中,全局做用域是 Window 對象,所以全部全局變量和函數都是做爲 window 對象的屬性和方法建立的。當某一個做用域中全部的代碼都執行完之後,做用域被銷燬, 做用域裏面的變量和函數,也隨之銷燬。(全局執行環境直到應用程序退出----例如關閉網頁或者瀏覽器------這時才被銷燬)  ----------- 《JS高級程序設計》4.2 app

環境棧:每一個函數都有本身的做用域,當執行流進入一個函數時,函數的做用域就會被推入一個環境棧中。函數執行完畢後,這個函數的做用域被環境棧彈出,把控制權交還給以前的做用域。函數

在一個頁面中,第一次載入JS代碼時建立一個全局執行環境,當調用一個 JavaScript 函數時,該函數就會進入相應的執行環境。若是又調用了另一個函數(或者遞歸地調用同一個函數),則又會建立一個新的執行環境,而且在函數調用期間執行過程都處於該環境中。當調用的函數返回後,執行過程會返回原始執行環境。於是,運行中的 JavaScript 代碼就構成了一個執行環境棧。(參考笨蛋的座右銘)。flex

舉個例子,下面程序的環境棧以下圖:ui

var cloth = 'shirt';

function f1() {
    var anotherCloth = 'pants';
    
    function f2() {
        var drink = 'juice';
    }
  f2(); }
f1();

 

 

 

二  做用域鏈spa

當代碼在一個做用域中執行時,會創造一個做用域鏈(scope chain)。做用域鏈的用途是,保證對執行環境有權訪問的全部變量和函數的有序訪問。做用域鏈的前端始終都是當前執行的代碼所在環境的變量對象。做用域鏈的下一個變量對象,來自包含(外部)環境,而在下一個變量對象則來自下一個包含環境。這樣一直延續到全局執行環境;全局執行環境始終都是做用域鏈的最後一個對象。

標識符解析是沿着做用域鏈一級級搜索標識符的過程。搜索過程始終都是從做用域鏈的前段開始,而後逐級的向後回溯,直到找到標識符爲止(若是找不到標識符,一般會致使錯誤發生。)

-----《JS高級程序設計》4.2

舉例來理解:

 1 var color = 'blue';
 2 
 3 function changeColor() {
 4     var anotherColor = "red"
 5     
 6     function swapColors() {
 7         var tempColor = anotherColor;
 8         anotherColor = color;
 9         color = tempColor;
10     
11     // 這裏能夠訪問 color、anotherColor 和 tempColor
12     }
13     
14     // 這裏能夠訪問 color 和 anotherColor。不能訪問 tempColor
15     
16     swapColors()
17 }
18   
19 // 這裏只能訪問 color
20 
21 changeColor()
22   

 

上面代碼在執行的時候有三個做用域:全局做用域、changeColor() 做用域和 swapColors() 做用域。他們的做用域鏈以下圖:

 

 

做用域鏈的本質是一個指向變量對象的指針列表,它只引用但不實際包含變量對象。

 

三  塊級做用域

塊級做用域,就是在 for、if  等裏面定義的變量,在 for、if 執行完畢之後,這些變量也會被銷燬。ES6 以前的版本,是沒有塊級做用域的。ES6 新增長了 let 和 const 關鍵字,就有了塊級做用域。例以下面的代碼:

 

1 if (true) {
2     var color = 'blue';
3 }
4   
5 alert(color);  // 'blue'       color 變量在 if 語句執行完之後並無被銷燬if 語句執行完之後,還會在外面訪問到 if 裏面的 color變量。

1 if (true) { 2 let color = 'blue'; 3 } 4 5 alert(color); //  color is not defined color 變量在 if 語句執行完畢之後,被銷燬,外部訪問不到 if 語句塊裏面定義的 color 變量。 

 

 1 for (var i=0; i < 10; i++) {
 2     var a = 1;
 3 }
 4 
 5 alert(i) // 10    
 6 

7 for (const i=0; i < 10; i++) { 8 var a = 1; 9 } 10 11 alert(i) // invalid assignment to const `i'

未解決的問題:

if 語句用 const 實現不了塊級做用域,for 語句用 let 實現不了會計做用域。這個疑惑還要後續再查找資料補充。

補充結果:let 用在塊做用域定義變量,而 const 在塊做用域定義常量。即在塊做用域中,一旦使用 const a = 1;那麼,在塊做用域中,就不能再給 a 賦值別的值了。由於,此時 a 已是一個常量了。

相關文章
相關標籤/搜索