重讀《深刻理解ES6》 —— 塊級做用域

1、關於變量聲明提高

在 ES5 中,咱們一般會使用 var 來聲明變量。在使用 var 聲明變量的時候,一般會遇到變量聲明提高的問題。這種機制會讓不少初學者迷惑不解。其實當咱們理解了一個變量一般包括聲明賦值兩個部分,這個問題也就不難理解了。編程

// 1
    console.log(a); // undefined
    var a = 3;
    
    // 2
    function foo() {
        console.log(b);  // undefined
        if (true) {
            var b = 2;
        }
    }
複製代碼

事實上,不管在全局做用域或者函數做用域中,只要經過 var 關鍵字聲明的變量,不論在哪裏聲明,都會被當成在當前做用域頂部聲明的變量。bash

// 1
    var a;
    console.log(a);
    a = 3;
    
    // 2
    function foo() {
    	var b;
        console.log(b);
        if (true) {
            b = 2;
        }
    }
複製代碼

2、塊級做用域

其實,變量提高的機制,不太符合咱們的編碼習慣,咱們經常但願代碼可以按照順序執行,這也符合通常人的邏輯習慣。爲此 ES6 引入了塊級做用域的概念。微信

塊級做用域其實就是詞法做用域,咱們的代碼寫在哪,就會在哪裏執行,這更符合咱們的編程習慣。咱們常說的塊包括函數內部{}之間的部分函數

爲了實現塊級做用域,ES6 採用 letconst 代替 var 來聲明變量。用 letconst 聲明的變量會把變量的做用域限制在當前的代碼塊中,而且聲明的變量不會被提高。另外,用 let 聲明的變量,在同一代碼塊內,禁止重複聲明。ui

// 一、變量不會提高
    console.log(a); // ReferenceError: a is not defined
    let a = 3;
    
    // 二、變量只能在當前做用域訪問
    if (true) {
        const b = 3;
        console.log(b); // 3
    }
    console.log(b); // ReferenceError: b is not defined
    
    // 三、禁止重複聲明
    function foo() {
        let c = 3;
        let c = 4; // Identifier 'c' has already been declared
    }
    foo();
複製代碼

3、let 與 const 的區別

letconst 均可以建立一個塊級做用域,惟一的區別是 const 用來聲明一個常量,它的值一旦被設定後不可修改。因此,用 const 聲明的常量必須初始化。編碼

// 一、不可更改
    const a = 1;
    a = 2; // TypeError: Assignment to constant variable.
    
    // 二、必須初始化
    const b; // SyntaxError: Missing initializer in const declaration
複製代碼

關於 const 聲明的變量不可修改,有一個值得注意的地方就是用 const 聲明一個對象。好比:spa

const tom = {
        age: 18,
        city: 'shanghai'
    };
    
    tom.age = 19; // 這是能夠的
複製代碼

咱們能夠理解爲,用 const 聲明瞭一個變量 tom,將一個對象的引用地址賦值給變量 tom,只要這個引用地址不發生變化,內部的值是能夠修改的。code

4、循環中塊級做用域

在 ES5 中,比較讓人頭疼的地方可能就是 for 循環了。在循環中,咱們用 var 聲明一個變量,循環結束後,咱們實際上是但願這個變量被銷燬的。但因爲 var 聲明的變量具備聲明提高的特性,因此當咱們用 for 循環的時候,每每會污染咱們的全局做用域。cdn

for (var i = 0; i < 10; i++) {
        // do something
    }
    console.log(i); // 10
    
    // 當循環結束的時候,其實咱們是但願變量 i 能夠被銷燬的。
    // 但其實它被留在了全局
複製代碼

這個時候,咱們使用 let 來聲明循環中的變量,就能夠輕易的解決這個問題。對象

for (let i = 0; i < 10; i++) {
        // do something
    }
    console.log(i); // ReferenceError: i is not defined
    
    // 能夠看到,循環結束,變量 i 就被銷燬了。 perfect~~
複製代碼

最後總結一下,letconst 幫助咱們解決了很多問題,咱們不會再爲變量提高引起的種種問題而困惑了,同時在循環中使用 let 來代替 var 能夠在循環結束的時候銷燬變量,避免無用的變量影響全局。而當前使用塊級綁定的最佳實踐是:默認使用 const ,只在肯定須要改變變量的值時,使用 let ,以最大化地避免錯誤的產生。

若是文章中有錯誤或表述不嚴謹的地方,歡迎指正。

也歡迎你們關注個人同名微信公衆號:李等等扣丁

相關文章
相關標籤/搜索