最近在Medium上看到一篇關於「變量提高」的文章,原文在此:《A guide to JavaScript variable hoisting with let and const》。爲了培養本身看英文文檔習慣且看懂的須要,就翻譯一下。談不上精確,歡迎指正。javascript
對於剛入門的JavaScript開發者時常難以理解「變量/方法」提高(hoisting)的獨特行爲。
接下來咱們要談論var,let,const聲明,那麼先了解變量提高就顯得更爲重要了。那就開始吧。java
JavaScript引擎用「var」處理全部變量聲明,無論在哪裏聲明,最後都會在函數做用域頂端(若是在函數內部聲明)或則在全局做用域頂端(在函數外部聲明)。這就是「提高」。
所以變量實際上可能在聲明它以前就已經被引擎得到了。程序員
在實際操做中看看效果..es6
// OUTPUT : undefined console.log(shape); var shape = square; // OUTPUT : square console.log(shape);
若是你來自C語言,你認爲在第一個console.log那裏就會拋出變量未定義的錯誤。但JavaScript解釋器預感和「提高」全部變量聲明到做用域頂端,而且在那進行初始化。
下面演示實際發生了什麼:ide
//declaration getting hoisted at the top var shape; // OUTPUT : undefined console.log(shape); shape = square; // OUTPUT : square console.log(shape);
另外一個例子是用函數做用域來更清楚的展現:函數
function getShape(condition) { // shape exists here with a value of undefined // OUTPUT : undefined console.log(shape); if (condition) { var shape = square; // some other code return shape; } else { // shape exists here with a value of undefined return false; } }
上面的例子能夠看出shape聲明被提高到了「getShape」函數做用域的頂端。這是由於「if/else」 不能像其餘語言那樣,建立局部做用域。在JavaScript裏,函數做用域實際上就是局部做用域了。所以,「shape」能夠在if塊以外,函數做用域內任意訪問,且值爲「undefined」。ui
JavaScript的這個默認行爲,既是優勢,又是缺點。沒有徹底掌握的話,會給咱們的代碼帶來細微且危險的bugs。spa
ES6 引入了塊級做用域,這讓開發者對變量有了更多的控制,且讓變量有靈活的生命週期。
塊級聲明在塊級/詞法做用域裏面聲明,他們在「{}」中被建立。翻譯
「let」語法跟「var」類似,只是用「let」標識符來替換「var」標識符進行變量聲明,其做用域範圍僅僅在聲明的那個代碼塊。
let聲明放在塊的頂端,所以只能在那個塊級做用域中訪問。
舉例:3d
function getShape(condition) { // shape doesn't exist here // console.log(shape); ReferenceError: shape is not defined if (condition) { let shape = square; // some other code return shape; } else { // shape doesn't exist here as well return false; } }
注意shape只存在if塊中,當在if塊外面訪問時會拋出一個錯誤,而不是象咱們以前用var聲明那樣輸出「undefined」。
提示:在同一個做用域內,若是已經使用var標識符聲明瞭變量,同時又用let標識符聲明同名變量時會拋出錯誤。
可是,若是在let聲明的變量做用域外,聲明同名變量是不會報錯的。(這種狀況也一樣適用於咱們即將談論的const聲明。)
舉例:
var shape = square; let shape = rectangle; // SyntaxError: Identifier 'shape' has already been declared
和
var shape = square; if (condition) { // doesn't throw an error let shape = rectangle; // more code } // No error
const聲明語法與let和var類似,生命週期與let相同,但你還要注意一些規則。
用const聲明的變量將像常量看待,所以它們的值在定義後是不能夠修改的。因爲這樣,每一個const變量都必須在聲明的同時進行初始化。
舉例:
// valid const shape = triangle; // syntax error: missing initialization const color; // TypeError: Assignment to constant variable shape = square;
然而,這個規則在聲明對象時有點不一樣。對象屬性的值能夠被修改!
const shape = { name: triangle, sides: 3 } // WORKS shape.name = square; shape.sides = 4; // SyntaxError: Invalid shorthand property initializer shape = { name: hexagon, sides: 6 }
在上面的例子中,咱們能夠看到shape對象屬性的值能夠被修改,由於咱們只改變shape包含的,而不是它自己。
咱們能夠總結說,const能夠防止整個綁定的修改,而不是綁定的值。
提示:屬性能夠改變。因此對於真正不可變的,請使用Immutable.js或Mori。
咱們都知道,若是咱們在使用let,const聲明定義的變量以前就使用這些變量,會拋出ReferenceError錯誤。 在進入做用域和不能訪問的這段時間,咱們稱爲暫時性死區。
提示:「暫時性死區」不是ECMAScript規範裏的正式定義,它只是在程序員中廣爲流行而已。
我我的推薦老是使用const,由於它不容易出錯。我還沒遇到須要使用var的狀況。
做爲基本規則,只在循環計數器中,或則你真的須要給變量重新賦值時用let。其餘地方,用const。我已經放棄使用循環,轉而選擇使用filter,map,reduce等方法。你也應該如此。
後記,此做者還有一篇關於方法提高的文章,到時候在搬來。