一 做用域(執行環境)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 變量在 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) //
未解決的問題:
if 語句用 const 實現不了塊級做用域,for 語句用 let 實現不了會計做用域。這個疑惑還要後續再查找資料補充。
補充結果:let 用在塊做用域定義變量,而 const 在塊做用域定義常量。即在塊做用域中,一旦使用 const a = 1;那麼,在塊做用域中,就不能再給 a 賦值別的值了。由於,此時 a 已是一個常量了。