【深入淺出ES6】塊級變數

Eric_zhang發表於2019-03-04

【深入淺出ES6】塊級變數

塊級繫結

var變數及變數提升

當使用var宣告變數時,js引擎會先將宣告語句提升至當前作用域最頂部(如果在函式內部,就是函式作用域的最頂部;如果是全域性作用域,就提升到全域性作用域最頂部)

function getValue(condition) {

    if (condition) {
        var value = "blue";

        // other code

        return value;
    } else {

        // value exists here with a value of undefined

        return null;
    }

    // value exists here with a value of undefined
}
複製程式碼

javascript 引擎處理後的結果

function getValue(condition) {

    var value;

    if (condition) {
        value = "blue";

        // other code

        return value;
    } else {

        return null;
    }
}
複製程式碼
延伸

關於編譯器對函式、變數提升的問題:

  • var和函式宣告會在程式碼執行前,被提升到作用域頂部
  • 函式表示式的方式,只會把變數提升
  • let不會被提升,做到了即用即宣告的目的,不會因為變數提升導致不可預估的異常
    // 函式宣告提升
    printName('hello world')
    var printName = function(name){
      console.log('name:',name) //name: hello world
    }
    // 函式表示式不會被提升
    printName('hello world') // Uncaught TypeError: printName is not a function
    var printName = function(name){
      console.log('name:',name)
    }
    /// 等效於
    var printName //變數提升
    printName('hello world') // Uncaught TypeError: printName is not a function
    printName = function(name){
      console.log('name:',name)
    }
    複製程式碼

塊級宣告

塊極作用域(又叫詞法作用域)被建立的情況:

  • 在函式內部
  • 在程式碼塊{}內部

塊極變數不存在變數提升的情況,塊極變數只能在作用域內訪問,外部訪問不了

let宣告
  • 在塊極作用域內使用,和var宣告的變數使用方法基本一致
const宣告
  • 常量宣告必須在宣告時完成初始化
  • 常量宣告會阻止對變數本身的修改,但是對於const宣告的物件,對其變數的某一成員屬性修改是不報錯的,但是不建議
const person = {
name: "Nicholas"
};
// 工作正常
person.name = "Greg";
// 丟擲錯誤
person = {
name: "Greg"
};
複製程式碼

注意點:

1. 同級作用內不能重複宣告

var count = 30;

// Syntax error
let count = 40;
複製程式碼

2. 暫時性死區

使用 let 或 const 宣告的變數,在當前同級作用域內在達到宣告處之前都是無法訪問的

當 JS 引擎檢視接下來的程式碼塊並發現變數宣告時,它會在面對 var 的情況下將宣告提升到函式或全域性作用域的頂部,而面對 let 或 const 時會將宣告放在暫時性死區內。任何在暫時性死區內訪問變數的企圖都會導致“執行時”錯誤(runtime error)。只有執行到變數的宣告語句時,該變數才會從暫時性死區內被移除並可以安全使用。

if (true) {
// 在同級塊極作用域內,不能在塊極變數宣告之前使用它
console.log(typeof value); //Uncaught ReferenceError: value is not defined
let value = "blue";
}
複製程式碼
// 在外層訪問則無所謂了,不會報語法錯誤
console.log(typeof value); // "undefined"
if (true) {
let value = "blue";
}
複製程式碼

3. 在迴圈中使用let塊極變數繫結,可以實現區域性作用域繫結的效果(for-in\for-of同樣適用)

var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i); });
}
funcs.forEach(function(func) {
func(); // 輸出數值 "10" 十次
});
複製程式碼

var被提升至最頂部,在迴圈中i變數是共享的同一個變數,所以在迴圈內建立的函式都擁有對同一i變數的引用,因此當最後執行函式時,列印的都是最後的i結果

var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 從 0 到 9 依次輸出
})
複製程式碼

在每次迴圈中,在區域性作用域中都會建立一個新的區域性塊極變數i,在每一次迭代中都是在自己的區域性作用域中,因此i變數不會被共享,當函式執行時,也就是列印對應作用域中的i變數的值

4. 全域性塊極繫結

  • 在全域性作用域,var宣告的變數會掛載到window物件上
  • 在全域性作用域,let宣告的變數不會掛載到window物件上,當訪問同名變數時,會優先取區域性塊極變數(遮蔽全域性變數,除非使用window.變數名訪問)

變數宣告最佳實踐

  • 預設情況下,優先使用const
  • 在確定宣告的變數會更改時,使用let

相關文章