let,const與var的比較

轉載自阮一峯老師的ES6入門,稍有修改es6

1.基本概念MDN

var聲明瞭一個變量,而且能夠同時初始化該變量。
let語句聲明一個塊級做用域的本地變量,而且可選的賦予初始值。
const 聲明建立一個只讀的常量,做用域與let相同。這不意味着常量指向的值不可變,而是變量標識符的值只能賦值一次。編程

2.基本用法

var爲你們所熟悉,在這裏再也不贅述。安全

let函數

let的用法相似於var,可是所聲明的變量,只在let命令所在的代碼塊內有效。設計

{  
  let a = 10;  
  var b = 1;  
}  
a // ReferenceError: a is not defined.  
b // 1

上面代碼在代碼塊之中,分別用let和var聲明瞭兩個變量。而後在代碼塊以外調用這兩 個變量,結果let聲明的變量報錯,var聲明的變量返回了正確的值。這代表,let聲明 的變量只在它所在的代碼塊有效。code

for循環的計數器,就很合適使用let命令。ip

for (let i = 0; i < 10; i++) {}

console.log(i);
//ReferenceError: i is not defined

上面代碼中,計數器i只在for循環體內有效,在循環體外引用就會報錯。內存

另外,for循環還有一個特別之處,就是循環語句部分是一個父做用域,而循環體內部 是一個單獨的子做用域。作用域

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

上面代碼輸出了3次abc,這代表函數內部的變量i和外部的變量i是分離的。get

const

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

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

上面代碼代表改變常量的值會報錯。

const聲明的變量不得改變值,這意味着,const一旦聲明變量,就必須當即初始化,不能留到之後賦值。

const foo;
// SyntaxError: Missing initializer in const declaration
上面代碼表示,對於const來講,只聲明不賦值,就會報錯。

const的做用域與let命令相同:只在聲明所在的塊級做用域內有效。

3.變量聲明提高與暫時性死區

變量聲明提高MDN

此段僅適用var聲明

因爲變量聲明(以及其餘聲明)老是在任意代碼執行以前處理的,因此在代碼中的任
意位置聲明變量老是等效於在代碼開頭聲明。這意味着變量能夠在聲明以前使用,這
個行爲叫作「hoisting」。「hoisting」就像是把全部的變量聲明移動到函數或者全 局代碼的開頭位置。

bla = 2
var bla;
// ...
// 能夠理解爲:   
var bla;  
bla = 2; 因爲這個緣由,咱們建議老是在做用域的最開始(函數或者全局代碼的開頭)聲明變 量。這樣可使變量的做用域變得清晰。 var命令會發生」變量提高「現象,即變量能夠在聲明以前使用,值爲undefined。這種

現象多多少少是有些奇怪的,按照通常的邏輯,變量應該在聲明語句以後纔可使用。

爲了糾正這種現象,let命令改變了語法行爲,它所聲明的變量必定要在聲明後使用, 不然報錯。

// var 的狀況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的狀況
console.log(bar); // 報錯ReferenceError
let bar = 2;

上面代碼中,變量foo用var命令聲明,會發生變量提高,即腳本開始運行時,變量foo 已經存在了,可是沒有值,因此會輸出undefined。變量bar用let命令聲明,不會發生 變量提高。這表示在聲明它以前,變量bar是不存在的,這時若是用到它,就會拋出一 個錯誤。

const的做用域與let命令相同:只在聲明所在的塊級做用域內有效。

if (true) {
  const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined

暫時性死區

只要塊級做用域內存在let命令,它所聲明的變量就「綁定」(binding)這個區域, 再也不受外部的影響。

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

上面代碼中,存在全局變量tmp,可是塊級做用域內let又聲明瞭一個局部變量tmp,致使後者綁定這個塊級做用域,因此在let聲明變量前,對tmp賦值會報錯。

ES6明確規定,若是區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯。

總之,在代碼塊內,使用let命令聲明變量以前,該變量都是不可用的。這在語法上,稱爲「暫時性死區」(temporal dead zone,簡稱 TDZ)。

if (true) {
  // TDZ開始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ結束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

上面代碼中,在let命令聲明變量tmp以前,都屬於變量tmp的「死區」。

「暫時性死區」也意味着typeof再也不是一個百分之百安全的操做。

typeof x; // ReferenceError
let x;
上面代碼中,變量x使用let命令聲明,因此在聲明以前,都屬於x的「死區」,只要用到該變量就會報錯。所以,typeof運行時就會拋出一個ReferenceError。

做爲比較,若是一個變量根本沒有被聲明,使用typeof反而不會報錯。

typeof undeclared_variable // "undefined"
上面代碼中,undeclared_variable是一個不存在的變量名,結果返回「undefined」。因此,在沒有let以前,typeof運算符是百分之百安全的,永遠不會報錯。如今這一點不成立了。這樣的設計是爲了讓你們養成良好的編程習慣,變量必定要在聲明以後使用,不然就報錯。

另外,下面的代碼也會報錯,與var的行爲不一樣。

// 不報錯
var x = x;

// 報錯
let x = x;
// ReferenceError: x is not defined

上面代碼報錯,也是由於暫時性死區。使用let聲明變量時,只要變量在尚未聲明完成前使用,就會報錯。上面這行就屬於這個狀況,在變量x的聲明語句尚未執行完成前,就去取x的值,致使報錯」x 未定義「。

ES6 規定暫時性死區和let、const語句不出現變量提高,主要是爲了減小運行時錯誤,防止在變量聲明前就使用這個變量,從而致使意料以外的行爲。這樣的錯誤在 ES5 是很常見的,如今有了這種規定,避免此類錯誤就很容易了。

總之,暫時性死區的本質就是,只要一進入當前做用域,所要使用的變量就已經存在了,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。

4.重複聲明

var是容許在相同做用域內重複聲明同一個變量的,而let與const不容許這一現象。

// 報錯
function () {
  let a = 10;
  var a = 1;
}

// 報錯
function () {
  let a = 10;
  let a = 1;
}

所以,不能在函數內部從新聲明參數。

function func(arg) {
  let arg; // 報錯
}

function func(arg) {
  {
    let arg; // 不報錯
  }
}

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

var message = "Hello!";
let age = 25;

// 如下兩行都會報錯
const message = "Goodbye!";
const age = 30;
相關文章
相關標籤/搜索