Let & Const

定義變數以及常數的方式。

在認識到這兩個宣告方式前,偶爾會因為全域變數被污染到而傷腦筋,但在使用了它們之後,再也不會遇到這樣的問題了,以下會分析這三種作用域的不同之處,並於後面詳細示範。

var

  • 函式作用域:只能以函式作為分界線,如放在判斷式或迴圈等語句中,仍然會暴露到全域範圍中。

let、const

  • 區塊作用域:只在一個{}內產生影響,較不易出錯。

# 作用域:

  1. var
function demo() {
  var a = 10;
}

if (true) {
  var b = 20;
}

console.log(a); //	a is not defined
console.log(b); //	20

var只會被函式區隔作用域,所以變數b一樣能從外部存取的到。

  1. let、const
function demo() {
  let a = 10;
}

if (true) {
  const b = 20;
}

console.log(a); //	a is not defined
console.log(b); //	b is not defined

作用域只在{}區塊內,較不易發生錯誤。

# 提升:

  1. var
console.log(a); //	undefined

var a = 5;

undefined也是一個值,表示已經被定義但尚未賦值。

  1. let、const
console.log(a); //	Uncaught ReferenceError: Cannot access 'a' before initialization

let a = 10;
console.log(b); //	Uncaught ReferenceError: Cannot access 'b' before initialization

const b = 20;

這會丟出錯誤訊息,是 ES6 規定給let、const的暫時性死區,讓變數提升的情況不會出現,減少運行上的錯誤。

# 定義:

  1. var
var a = 5;
var a = 10;

console.log(a); //	10

被重新宣告或重新賦值皆是允許的。

  1. let
let a = 5;
let a = 10;

console.log(a); //	Uncaught SyntaxError: Identifier 'a' has already been declared

透過let宣告的變數,無法再次進行宣告。

let a = 5;
a = 10;

console.log(a); //	10

賦予新的值是可以的。

  1. const
const a = 5;
const a = 10;

console.log(a); //	Uncaught SyntaxError: Identifier 'a' has already been declared

透過const宣告的常數,無法再次進行宣告。

const a = 5;
a = 10;

console.log(a);

無法賦予新的值。

const a = {};
a.demo = 'test';

console.log(a); //	{demo: "test"}

const b = [];
b[0] = 'test';

console.log(b); //	["test"]

如果今天宣告的值是物件或陣列,裡面的值是可以改變的。

# 實例:

  1. var
for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

這是一個經典的題目,當一秒後會得到五個 5 被打印出來,因為全域變數i最後被賦予的值就是 5。

  1. let
for (let i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i); //	0	1	2	3	4
  }, 1000);
}

由於區塊作用域造成的結果,在每次的for迴圈執行時,用let宣告的變數都會重新綁定一次。

  1. const
for (const i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i); //	0
  }, 1000);
}

只會印出第一個 0,接著會出現Uncaught TypeError,因為const的值是不能被重複賦予的。