天天看點

Let和Const差別,詳細版本

let:聲明的是變量

1、不存在變量提升

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

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

上面代碼中,變量foo用var聲明,會發生變量提升,即腳本開始運作時,變量foo已經存在了,但是沒有值,是以會輸出undefined。變量用let聲明,不會發生變量提升。這表示在聲明它之前,變量bar是不存在的,這時如果用到他,就會抛出一個錯誤。

2、暫時性死區,先聲明在使用

var tmp = 123;

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

上面代碼中,存在全局變量tmp,但是塊級作用域内let又聲明了一個局部變量tmp,導緻後者綁定這個塊級作用域,是以在let聲明變量前,對tmp指派報錯,先聲明再使用。

3、不允許重複聲明

let不允許在相同作用域内,重複聲明同一個變量。

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

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

4、塊級作用域

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 s = 'hello';

for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}

console.log(i); // 5      

上面代碼中,變量i隻用來控制循環,但是循環結束後,它并沒有消失,洩漏成了全部變量。

ES6的塊級作用域,let實際上為javascript新增的塊級作用域。

function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5      

上邊代碼,有兩個代碼塊,都聲明了變量n,運作後輸出5。這表示外層代碼塊不受内層代碼塊的影響。如果兩次都使用var定義變量n,最後輸出的值才是10。

ES6 允許塊級作用域的任意嵌套。

{{{{{let insane = 'Hello World'}}}}};      

const:常量

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

const的作用域與let指令相同:隻在聲明所在的塊級作用域内有效

const指令聲明的常量也是不提升,同樣存在暫時性死區,隻能在聲明的位置後面使用。

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

const foo = {};

// 為 foo 添加一個屬性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only      

上面代碼中,常量foo儲存的是一個位址,這個位址指向一個對象。不可變的隻是這個位址,即不能把foo指向另一個位址,但對象本身是可變的,是以依然可以為其添加新屬性

ES6 聲明變量的六種方法

ES5 隻有兩種聲明變量的方法:var指令和function指令。ES6 除了添加let和const指令,後面章節還會提到,另外兩種聲明變量的方法:import指令和class指令。是以,ES6 一共有 6 種聲明變量的方法。

let和const的相同點:

① 隻在聲明所在的塊級作用域内有效。

② 不提升,同時存在暫時性死區,隻能在聲明的位置後面使用。

③ 不可重複聲明。

let和const的不同點:

① let聲明的變量可以改變,值和類型都可以改變;const聲明的常量不可以改變,這意味着,const一旦聲明,就必須立即初始化,不能以後再指派

const i ; // 報錯,一旦聲明,就必須立即初始化
const j = 5;
j = 10; // 報錯,常量不可以改變      

② 數組和對象等複合類型的變量,變量名不指向資料,而是指向資料所在的位址。const隻保證變量名指向的位址不變,并不保證該位址的資料不變,是以将一個複合類型的變量聲明為常量必須非常小心。

const arr = [];
// 報錯,[1,2,3]與[]不是同一個位址
arr = [1,2,3];
const arr = [];
// 不報錯,變量名arr指向的位址不變,隻是資料改變
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
console.log(arr.length); // 輸出:3      

若想讓定義的對象或數組的資料也不能改變,可以使用object.freeze(arr)進行當機。當機指的是不能向這個對象或數組添加新的屬性,不能修改已有屬性的值,不能删除已有屬性。

const arr = [];
Object.freeze(arr);
// 不報錯,但資料改變無效
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
console.log(arr.length); // 輸出:0