跟着阮神學ES6——變量與做用域

let 命令是什麼

let 是一個用來聲明變量的命令。它的用法相似於var ,可是所聲明的變量,只在let 命令所在的代碼塊內有效。javascript

let 命令的特性?

  1. 所聲明的變量的塊內有效性
  2. 無初始化的變量提高
  3. 暫時性死區
  4. 不容許重複聲明

變量提高是什麼?

JavaScript引擎中,代碼會在執行上下文中執行。而在執行上下文的建立階段,聲明的各類類型變量 (var, let, const, function, function*, class) 都會被添加到詞法環境中。html

  1. let , const, class 的「建立」過程被提高了,可是「初始化」沒有提高。
  2. var 的「建立」過程被提高了,而且會被「初始化」爲undefined。
  3. function, function* 的「建立」「初始化」和「賦值」都被提高了。
  4. function, function*提高的優先級別更高,更早被添加到詞法環境中。
  5. let, const, class, function, function*被添加到詞法環境中,而 var 被添加到變量環境中。
  6. 變量環境也是一個詞法環境,只用來存儲 var 變量綁定。

特別的for 循環

使用for循環時,發現let居然能夠重複定義同名變量:java

for (let i = 0; i < 3; i++) {
    let i = 'abc';
    console.log(i);
}
// abc
// abc
// abc
複製代碼

總結:這代表函數內部的變量i 與for循環變量i 不在同一個做用域。循環變量的那部分是一個父做用域,而循環體內部是一個單獨的子做用域。web

爲何須要塊級做用域?

ES5 只有全局做用域和函數做用域,沒有塊級做用域,這帶來不少不合理的場景。編程

內層變量可能會覆蓋外層變量

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined
複製代碼

用來計數的循環變量泄露爲全局變量

var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5
複製代碼

上面代碼中,變量i只用來控制循環,可是循環結束後,它並無消失,泄露成了全局變量。數組

ES6塊級做用域特色

  1. ES6 容許塊級做用域的任意嵌套瀏覽器

  2. ES6 的塊級做用域必須有大括號markdown

  3. 內層做用域能夠定義外層做用域的同名變量數據結構

    {{{{
      let insane = 'Hello World';
      {let insane = 'Hello World'}
    }}}};
    複製代碼
  4. 匿名當即執行函數表達式部分功能被替代模塊化

    // IIFE 寫法
    (function () {
      var tmp = ...;
      ...
    }());
    
    // 塊級做用域寫法
    {
      let tmp = ...;
      ...
    }
    複製代碼
  5. 容許在塊級做用域之中聲明函數

    ES6 規定,塊級做用域之中,函數聲明語句的行爲相似於let,在塊級做用域以外不可引用。

    1. ES5 規定,函數只能在頂層做用域和函數做用域之中聲明,不能在塊級做用域聲明。
    2. 瀏覽器沒有遵照這個規定,爲了兼容之前的舊代碼,仍是支持在塊級做用域之中聲明函數,不會報錯。
    3. 爲減輕所以產生的不兼容問題,ES6 在附錄 B裏面規定,瀏覽器能夠有本身的行爲方式(相似於var)。
    4. 考慮到環境致使的行爲差別太大,應避免在塊級做用域內聲明函數。
    5. 嚴格模式下,函數只能聲明在當前做用域的頂層。

const 命令的特色

  1. const聲明一個只讀的常量。一旦聲明,常量的值就不能改變。

  2. 只在聲明所在的塊級做用域內有效(與let命令相同)。

  3. const命令聲明的常量也是無初始化提高,一樣存在暫時性死區。

  4. const聲明的常量,也與let同樣不可重複聲明。

  5. const僅僅保證指向的內存地址數據不得改動。

    對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,所以等同於常量。但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(即老是指向另外一個固定的地址),至於它指向的數據結構則是可變的。

  6. 若是想凍結對象,應該使用Object.freeze方法。

ES6 聲明變量的六種方法

  1. var
  2. function
  3. let
  4. const
  5. import
  6. class

var命令和function命令是ES5 中僅有的兩種聲明變量的方法。letconst命令,import命令和class命令則是ES6新增的聲明變量的方法。

全局變量與頂層對象

  1. 頂層對象,在瀏覽器環境指的是window對象,在 Node 指的是global對象。
  2. ES5 之中,頂層對象的屬性與全局變量是等價的。
  3. ES6 之中, var命令和function命令聲明的全局變量,依舊是頂層對象的屬性。
  4. ES6 之中, let命令、const命令、class命令聲明的全局變量,不屬於頂層對象的屬性。

頂層對象與全局變量等價的缺點?

  1. 無法在編譯時就報出變量未聲明的錯誤
  2. 容易不知不覺地就建立了全局變量
  3. 頂層對象的屬性是處處能夠讀寫的,這很是不利於模塊化編程
  4. 頂層對象是一個有實體含義的對象(window指瀏覽器的窗口對象),含義混淆。

ES2020爲何新增globalThis對象?

JavaScript 語言存在一個頂層對象,它提供全局環境(即全局做用域),全部代碼都是在這個環境中運行。可是,頂層對象在各類實現裏面是不統一的。

  • 瀏覽器裏面,頂層對象是window,但 Node 和 Web Worker 沒有window

  • 瀏覽器和 Web Worker 裏面,self也指向頂層對象,可是 Node 沒有self

  • Node 裏面,頂層對象是global,但其餘環境都不支持。

相關文章
相關標籤/搜索