首先我們應該知道js引擎在讀取js代碼時會進行兩個步驟:
- 第一個步驟是解釋。
- 第二個步驟是執行。
所謂解釋就是會先通篇掃描所有的Js代碼,然后把所有聲明提升到頂端,第二步是執行,執行就是操作一類的。
我們先來看個簡單的變量提升案例吧
a = 'javascript';
var a;
console.log(a);//'javascript'
console.log(b);//undefined
var b='javascript'
遇到 script 標簽的話 js 就進行預解析,將變量 var 和 function 聲明提升,但不會執行 function,然后就進入上下文執行,上下文執行還是執行預解析同樣操作,直到沒有 var 和 function,就開始執行上下文。如:
a=5;
show();
var a;
function show(){};
預解析:
function show(){};
var a;
a=5;
show();
需要注意都是函數聲明提升直接把整個函數提到執行環境的最頂端。
那么let/const和var又有什么區別呢??
- let/const是使用區塊作用域;var是使用函數作用域。
- 在let/const聲明之前就訪問對應的變量與常量,會拋出ReferenceError錯誤;但在var聲明之前就訪問對應的變量,則會得到undefined。
console.log(aVar) // undefined
console.log(aLet) // causes ReferenceError: aLet is not defined
var aVar = 1
let aLet = 2
會出現這樣的情況是因為let/const擁有“暫時性死區(TDZ)”。
什么是暫時性死區?
當程序的控制流程在新的作用域(module, function或block作用域)進行實例化時,在此作用域中的用let/const聲明的變量會先在作用域中被創建出來,但因此時還未進行詞法綁定,也就是對聲明語句進行求值運算,所以是不能被訪問的,訪問就會拋出錯誤。所以在這運行流程一進入作用域創建變量,到變量開始可被訪問之間的一段時間,就稱之為TDZ(暫時死區)。
結論:let/const聲明的變量,的確也是有提升(hoist)的作用。這個是很容易被誤解的地方,實際上以let/const聲明的變量也是會有提升(hoist)的作用。提升是JS語言中對於變量聲明的基本特性,只是因為TDZ的作用,並不會像使用var來聲明變量,只是會得到undefined而已,現在則是會直接拋出ReferenceError錯誤,而且很明顯的這是一個在運行期間才會出現的錯誤。
ES6 規定暫時性死區和let、const語句不出現變量提升,主要是為了減少運行時錯誤,防止在變量聲明前就使用這個變量,從而導致意料之外的行為。這樣的錯誤在 ES5 是很常見的,現在有了這種規定,避免此類錯誤就很容易啦~
原文地址:https://segmentfault.com/a/1190000017352156