Louis's blog
GitHub
GitHub
  • 瀏覽器運作原理
  • 閉包
  • this
  • arguments 和 array-like
  • apply、call、bind
  • 函式程式設計
  • 物件和原型
  • 原型鏈和繼承
  • ES6 和 Class
  • ES6 中新增的數據類型
  • ES6 語法糖
  • var、let、const
  • ES7~ES12
  • Strict Mode
  • 補充
  • Proxy 和 Reflect
  • Promise
  • Iterator
  • 生成器
  • async、await
  • Event loop
  • 錯誤處理
  • 模塊化
  • 套件管理工具
  • JSON
  • WebStorage
  • IndexDB
  • Cookie
  • BOM
  • DOM
  • 防抖(debounce)和節流(throttle)
  • Deep copy
  • 事件總線

var、let、const

在 ES5 中聲明變數都是使用 var 關鍵字,從 ES6 開始新增了兩個關鍵字可以聲明變數:let、const。

基本使用

let bar = 'bar'

const 意思即為常量( constant ),代表不可被修改。

const foo = 'abc'

但如果是賦值為某個引用類型,則可以修改其內部的屬性或元素,例如:

const obj = {
  foo: 'foo'
}
obj.foo = 'bar'

相對於 var , let 和 const 所定義過的變數名稱都不可以重複聲明。

作用域提升

var 有作用域提升,那 let 有作用域提升嗎?運行以下程式碼:

console.log(foo)
let foo = 'foo'

可以獲得錯誤 Cannot access 'foo' before initialization ,意思是 foo 在初始化前無法被訪問,所以實際上這些變數會提前被創建,但是不可以被訪問,直到這些變數被賦值。

由於作用域提升沒有準確的定義,所以從不可被訪問的角度來說,可以說 let 和 const 是沒有作用域提升的。

let、const 和 window

在全局通過 var 聲明一個變數時,這個變數會作為屬性放到 window 物件中:

var foo = 'foo'
console.log(window.foo)

而 let 和 const 作為新的語法被 JS 引擎分開處理,放到一張獨立的哈希表 (Hash map) 中。

塊極作用域

在 ES5 中只有兩個東西會形成作用域,第一個是全局作用域,第二個是函數作用域。

在 ES6 中的 let、const、class 存在塊極作用域,外部無法訪問作用域內部的變數:

{
  let foo = 'foo'
}

console.log(foo) // foo is not defined

if 後面跟的就是塊極作用域:

if (true) {
  let foo = 'foo'
}
console.log(foo) // foo is not defined

switch 和 for 迴圈也是:

var bar = 'a'
switch (bar) {
  case 'a':
    let foo = 'foo'
    break

  default:
    break
}
console.log(foo) // foo is not defined
for (let i = 0; i < 10; i++) {
  console.log('Hello World' + i)
}

console.log(i) // i is not defined

塊極作用域的用處

for (var i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i)
  })
}

執行以上程式碼會得到十個 10 的打印,因為 var 沒有塊極作用域,所以變數是保存在全局中,要想要分別打印出每個 i 的值,在 ES5 中可以使用函數作用域。

for (var i = 0; i < 10; i++) {
  ;(function (n) {
    setTimeout(() => {
      console.log(n)
    })
  })(i)
}

有了 es6 就不用寫這麼複雜了:

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(n)
  })
}

暫時性死區

在 ES6 中,let 和 const 在聲明之前,變數是都不可以被問的,社區將其稱為暫時性死區(temporal dead zone)。

類似以下這種程式碼,只要有使用到 let,都是不能被訪問的:

var foo = 'foo'

if (true) {
  console.log(foo)

  let foo = 'abg'
}

報錯:

ReferenceError: Cannot access 'foo' before initialization

var、const、let 的選擇

var 的特殊性:比如作用域提升、window 全局物件屬性、沒有塊極作用域等,這些都是歷史遺留的問題,是在 JavaScript 設計之初的一些缺陷,所以在實際業務中還是以最新的標準來編寫程式碼,也就是不再用 var 來定義變數。

ES6 中的 const 可以保證數據的安全性,所以在開發中優先使用,只有在明確該變數會在後續進行修改時再使用 let。

Edit this page
Last Updated:
Contributors: louis, louis61619
Prev
ES6 語法糖
Next
ES7~ES12