譯:用let 和 const 來指導JavaScript 的變量提高

圖片描述

最近在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聲明

「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聲明

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.jsMori

暫時性死區

咱們都知道,若是咱們在使用let,const聲明定義的變量以前就使用這些變量,會拋出ReferenceError錯誤。 在進入做用域和不能訪問的這段時間,咱們稱爲暫時性死區。
提示:「暫時性死區」不是ECMAScript規範裏的正式定義,它只是在程序員中廣爲流行而已。
圖片描述

我我的推薦老是使用const,由於它不容易出錯。我還沒遇到須要使用var的狀況。
做爲基本規則,只在循環計數器中,或則你真的須要給變量重新賦值時用let。其餘地方,用const。我已經放棄使用循環,轉而選擇使用filter,map,reduce等方法。你也應該如此。

後記,此做者還有一篇關於方法提高的文章,到時候在搬來。

相關文章
相關標籤/搜索