JavaScript中var、let、const的區別。
var、let、const的區別。
ES5中宣告變數可以使用var、和function,但是使用var宣告的變數會有一定的缺陷。所以ES6(ECMAScript 6)提出了let、const這兩個宣告變數的方式,用來彌補ES5中var的不足。
var 、let、const 的區別大致可以分為五種:
- 是否存在變數提升。
- 是否可以修改變數。
- 是否存在塊級作用域。
- 是否存在暫時性死區。
- 是否可以重複宣告變數。
變數提升
在ES5提出的var宣告變數的方式中,存在變數提升(所謂變數提升就是將當前宣告的變數提升到當前作用域的最頂端),這種方式多多少少都有一些奇怪,按照一般的邏輯,變數應該在宣告語句之後才可以使用。
為了糾正這種現象,所以說ES6提出的let命令改變了語法行為。
var 存在變數提升;let、const不存在變數提升
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2;
//const 的情況
console.log(bar) // 報錯ReferenceError
const bar =2 ;
是否可以修改變數
var 和let可以修改變數。
const不可以修改變數,因為const宣告的是一隻讀個常量,一但宣告,常量就不能更改,不然的話就會報錯。
const a=3.1415;
a;
a=3;//會報錯
是否存在作用域
什麼是塊級作用域:
ES5中的作用域有:全域性作用域、函式作用域。不存在塊級作用域的概念,這會帶來很多不合理的場景。
第一種情況,內部變數可能會覆蓋外層變數。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
if程式碼塊的外部使用外層的tmp變數,內部使用內層的tmp變數,函式f執行後,輸出結果為undefined,原因在於變數提升,導致內層的tmp變數覆蓋了外層的tmp變數。
第二種情況,用來計數的迴圈變數洩露為全域性變數。
var tmp = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(tmp[i]);
}
console.log(i); // 5 i迴圈結束後,洩露成了全域性變數
變數i只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數
ES6(ECMAScript 6)中新增了塊級作用域,塊級作用域使用{}包括,if判斷和for迴圈中的{}也屬於塊級作用域。
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
在兩個程式碼塊中,都聲明瞭變數n,執行後輸出 5。這表示外層程式碼塊不受內層程式碼塊的影響。如果兩次都使用var定義變數n,最後輸出的值才是 10。
是否存在暫時性死區
let和const存在暫時性死區。即只要塊級作用域記憶體在let命令,它所宣告的變數就“繫結”(binding)這個區域,不再受外部的影響。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
//以上程式碼if後面{}形成了塊級作用域,由於使用let聲明瞭tmp,則這個變數就綁定了塊區域,在宣告之前使用,會報錯。
在程式碼塊內,使用let命令宣告變數之前,該變數都是不可用的。這在語法上,稱為“暫時性死區”(temporal dead zone,簡稱 TDZ)。
總之,暫時性死區的本質就是,只要一進入當前作用域,所要使用的變數就已經存在了,但是不可獲取,只有等到宣告變數的那一行程式碼出現,才可以獲取和使用該變數。
是否允許重複宣告變數?
var允許重複宣告變數。
let和const在同一作用域不允許重複宣告變數
var f = 4;
var f = 5;
console.log(5) //5
let g = 6;
let g = 7;
console.log(7) //SyntaxError: Identifier 'g' has already been declared
const h = 8;
const h = 9;
console.log(h) //SyntaxError: Identifier 'g' has already been declared