原文連接:https://acrens.github.io/2017/01/22/2017-01-22-TDZ/
春節快到了,假期也快到了,空閒之餘刷個微博,看見 @ruanyf 提出了一個問題與 TDZ 有關,可是貌似阮大當時尚未意識到這個問題,多虧一些其餘業內同仁提出了與 TDZ 相關;固然,以阮大的能力這都不是事。因爲當時我自己也還不知道 TDZ 這一回事沒有看懂,因此就花了一些時間去搞清楚什麼是 TDZ 及TDZ會帶來一些什麼問題,本文主要是用於介紹我對 TDZ 的一些理解,若有問題,多謝指出。javascript
案例一java
代碼git
let y = 1; function foo(x = y, y) { console.log(x); } foo(); // ReferenceError: y is not defined
解讀es6
當函數存在默認參數時,且調用方法不傳任何參數,會存在三個做用域環境;github
全局做用域、參數做用域、函數體做用域;ecmascript
當執行 foo 函數時,參數做用域在 x = y 以後才定義 let y,注意:let 定義,因此根據 let 定義變量的做用知道 x = y 確定會報錯;函數
代碼翻譯:將以上代碼翻譯以後能夠按下面代碼片斷閱讀更易於理解測試
function analysis() { "use strict"; let y = 1; function foo() { let x = arguments[0] !== (void 0) ? arguments[0] : y; // y not defined let y = arguments[1]; } foo(); return {}; }
案例二google
代碼翻譯
let y = 1; function foo(x = function(){console.log(y)}, y = 2) { x(); // 2 y = 3; x(); // 3 } foo(); console.log(y); //1
解讀
當函數存在默認參數時,且調用方法不傳任何參數,會存在三個做用域環境;
全局做用域、參數做用域、函數體做用域;
當執行 foo 函數時,x 被申明爲匿名函數變量,此時函數並未被執行,因此正常;以後定義 y 值爲 2,此時調用 x() 輸出的固然是變量 y 的值,以後繼續修改 y 的值,再繼續調用 x(),輸出 y 最新值 3;當執行外部 console.log(y) 時並不能訪問內部函數變量,訪問的變量是當前域下的 y = 1 的值 1,因此輸出 1;
代碼翻譯:將以上代碼翻譯以後能夠按下面代碼片斷閱讀更易於理解
function analysis() { "use strict"; let y = 1; function foo() { let x = arguments[0] !== (void 0) ? arguments[0] : function() { console.log(y); }; let y = arguments[1] !== (void 0) ? arguments[1] : 2; x(); // 2 y = 3; x(); // 3 } foo(); console.log(y); // 1 return {}; }
案例三
代碼
let y = 1; function foo(x = function(){console.log(y)}) { let y = 3; x(); // 1 } foo();
解讀
當函數存在默認參數時,且調用方法不傳任何參數,會存在三個做用域環境;
全局做用域、參數做用域、函數體做用域;
當執行 foo 函數時,x 被賦值爲一個匿名函數的變量,且存在與參數做用域內,let y = 3 會被定義到函數體做用域內,屬於參數做用域的內部函數;當 x() 執行時是在函數體做用域定被調用,可是其定義是在參數做用域,因此執行環境是在參數做用域內,此時在參數做用域沒有定義 y 變量,也不能訪問內部函數 funBody 內部定義的變量 y,此時往上級函數查找是否存在 y 被定義,若是被定義則輸出其值,因此輸出最外層變量 y 的值 1;
代碼翻譯:將以上代碼翻譯以後能夠按下面代碼片斷閱讀更易於理解
function analysis() { "use strict"; let y = 1; function foo() { let x = arguments[0] !== (void 0) ? arguments[0] : function() { console.log(y); }; function funBody() { let y = 3; x(); } funBody(); } foo(); return {}; }
案例四
代碼
function foo(x = function(){console.log(y)}) { let y = 3; x(); // // ReferenceError: y is not defined } foo();
解讀
當函數存在默認參數時,且調用方法不傳任何參數,會存在三個做用域環境;
全局做用域、參數做用域、函數體做用域;
當執行 foo 函數時,x 被賦值爲一個匿名函數的變量,且存在與參數做用域內,let y = 3 會被定義到函數體做用域內,屬於參數做用域的內部函數;當 x() 執行時是在函數體做用域定被調用,可是其定義是在參數做用域,因此執行環境是在參數做用域內,此時在參數做用域沒有定義 y 變量,也不能訪問內部函數 funBody 內部定義的變量 y,此時往上級函數查找是否存在 y 被定義,若是被定義則輸出其值,不然報 y 沒有被定義錯誤,此案例只是案例三的一種測試;
代碼翻譯:將以上代碼翻譯以後能夠按下面代碼片斷閱讀更易於理解
function analysis() { "use strict"; function foo() { let x = arguments[0] !== (void 0) ? arguments[0] : function() { console.log(y); }; function funBody() { let y = 3; x(); } funBody(); } foo(); return {}; }
以上核心部分在代碼翻譯部分,經過配合一下資料及我的的理解,翻譯出通俗易懂的代碼: