ES6規範新增了let、const兩種變量聲明方式,項目中也常常要用到,今天藉着溫習ES6語法,來總結let 、const、var的區別。javascript
來看下面三段代碼java
console.log(a); // undefined var a = 2;
console.log(b); // Uncaught ReferenceError: b is not defined let b = 2;
console.log(c); // Uncaught ReferenceError: c is not defined const c = 2;
用var聲明的變量,會在其做用域中發生變量提高,js默認給變量一個undefined值。es6
可是,在ES6中使用let/const聲明的變量,不存在變量提高過程。也就是說,在使用let/const聲明的變量,聲明前訪問它,都會報錯。閉包
代碼塊內,使用let命令聲明變量以前,該變量都是不可用的。這在語法上,稱爲「暫時性死區」(temporal dead zone,簡稱 TDZ)。
let a = 'global'; if (true) { a = 'block'; // Uncaught ReferenceError: a is not defined let a; }
上述代碼中,if代碼塊裏,在let聲明變量a以前,都是a的"暫時性死區",在該範圍內訪問a都會報錯。
因而可知,塊級做用域內存在let聲明的話,它所聲明的變量就綁定在這個塊級做用域,再也不受外部影響。函數
let 和 const 命令聲明的變量不容許重複聲明;而使用var聲明變量,能夠屢次重複聲明一個同名變量,但最終變量的值爲最後一次聲明賦值的結果。指針
var a = 10; var a = 'abc'; var a = 'last value'; console.log(a); // last value
let與const在相同做用域聲明重複的變量會報錯code
let a = 10; let a = 20; // Uncaught SyntaxError: Identifier 'a' has already been declared
var和let同時聲明同一個變量,也是報一樣的錯誤對象
let b = 10; var b = 20; // Uncaught SyntaxError: Identifier 'b' has already been declared
或先var,再letip
var c = 10; let c = 20; // Uncaught SyntaxError: Identifier 'c' has already been declared
這裏就涉及到一個最經典的問題:內存
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); // 5 5 5 5 5 }); }
這個問題的解決可使用閉包等,ES6的let爲這個問題提供了新的解決方法:
for (let i = 0; i < 5; i++) { setTimeout(function() { console.log(i); // 0 1 2 3 4 }); }
使用let聲明的變量僅在塊級做用域內有效。 i在循環體內的局部做用域,不受外界影響。
在ES6以前,都是用var來聲明變量,並且JS只有函數做用域和全局做用域,沒有塊級做用域,因此花括號{}限定不了var聲明變量的訪問範圍。
{ var a = 10; } console.log(a); // 10 { let b = 9; // es6的let: b變量只在花括號內有效 } console.log(b); // Uncaught ReferenceError: b is not defined
使用var聲明的全局變量,會被JS自動添加在全局對象window上,但let和const不會
let a = 10; console.log(window.a); // undefined var b = 20; console.log(window.b); // 20 const c = 30; console.log(window.c); // undefined
因爲const用來聲明常量,一旦聲明,就必須當即初始化,並且聲明以後值不能改變。
const a = 10; a = 20; // Uncaught TypeError: Assignment to constant variable.
常量的值不變,其實是指常量指向的那個內存地址中所保存的數據不可更改。
對於基本數據類型(數值,字符串、布爾值),他們自己具體的值就保存在常量所指向對應的棧內存地址中,因此修改值就等於修改棧內存地址,這顯然不容許會報錯。
可是,若是一個常量的值是一個引用類型值,那麼常量所指向的內存地址(堆內存)中實際保存的是指向該引用類型值的一個指針(也就是引用類型值在內存中的地址)。因此const只能保證該引用類型地址不變,但該地址中的具體數據是能夠變化的。
以下代碼:
const obj = {}; obj.a = 3; console.log(obj); // {a: 3} // 當obj指向了另外一個對象,即obj中保存的地址發生了變化,即會報錯 obj = {}; // Uncaught TypeError: Assignment to constant variable.
在開發的時候,聲明變量咱們應該少使用var,避免產生沒必要要的全局變量。當須要改變變量的值時聲明用let,對於須要寫保護的變量或定義常量使用const。