前端小知識:var和let究竟有哪些區別

前端小知識:var和let究竟有哪些區別

來自互聯網

前置知識

我們都知道let是ES6中的語法,和var一樣,作用都是用來聲明變量的,那為什麼有了var還要新發明一個let呢?它們倆究竟有什麼區別呢?

以下就總結了let和var聲明變量的幾點區別:

1.let會形成塊級作用域

塊級作用域:即let聲明的變量只在let命令所在的代碼塊內有效

  • 先看一個直觀的例子
for(let i=0;i<10;i++){
// ... 
}
console.log(i);	//// ReferenceError: i is not defined

解析:

其中變量i用let定義,會形成塊級作用域,因此變量i只在for循環中有效,當在全局環境中去尋找時是找不到的,所以程序報錯;

如果用var定義變量i,i會在全局環境中,因此不會報錯,因為var沒有塊級作用域,只有全局作用域函數作用域

1.1常見經典問題

需求:for循環初始化一個數組,數組中每個元素都為一個函數

var定義變量版本:

var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10

分析:

上面代碼中,變量i是var命令聲明的,因此變量 i 是在全局環境中的。其中變量 i 作為數組 index 時是每次循環都確定一次的,而函數中的變量 i 只有在函數運行時才會確定。因此在 for 循環結束時,數組 a 中每個元素的函數中的變量 i 都是不確定的。

當最後我們運行函數時,我們才會去全局環境裡尋找確定變量 i ,而此時全局環境中的變量 i 經過 for 循環之後已經給變成了10,因此最後輸出的變量 i 自然是10。

  • 這自然不是我們想要的結果,那應該如何實現我們的需求呢?
  • 答案是改用let定義即可

let定義變量版本:

var a = [];
for (let i = 0; i < 10; i++) {
 a[i] = function () {
 console.log(i);
 };
}
a[6](); // 6

分析:

上面代碼中,變量i是let聲明的,具有塊級作用域,因此每輪循環中的i只在本輪循環作用域內有效,也就是說每一循環中的變量 i 都在不同的作用域內,因此最後運行函數時,會到當初定義變量 i 的那輪循環作用域中去尋找變量 i ,因此最後輸出的是自然是 6。

  • 你可能會問,如果每一輪循環的變量i都是重新聲明的,那它怎麼知道上一輪循環的值,從而計算出本輪循環的值?
  • 這是因為 JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的變量i時,就在上一輪循環的基礎上進行計算。

1.2.重點注意點

for循環還有一個特別之處,就是

設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域

  • 例子:
for (let i = 0; i < 2; i++) {
 let i = 'bcd';
 console.log(i);
}
// bcd
// bcd

分析:

上面代碼正確運行,輸出了 3 次bcd。這表明函數內部的變量i與循環變量i不在同一個作用域,有各自單獨的作用域(重點記憶)

​​

2.let命令不存在變量提升

var命令會發生“變量提升”現象,即變量可以在聲明之前使用,值為undefined。按照一般的邏輯,變量應該在聲明語句之後才可以使用,為了糾正這種現象,let命令改變了語法行為,它所聲明的變量一定要在聲明後使用,否則報錯。

  • 例子:
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2; 

3.let聲明變量存在暫時性死區(即變量會綁定某個區域,不受外部影響)

  • 例子
if (true) {
 tmp = 'abc'; // ReferenceError
 let tmp;
}
//上面代碼中,存在全局變量tmp,但是塊級作用域內let又聲明瞭一個局部變量tmp,
導致後者綁定這個塊級作用域,所以在let聲明變量前,對tmp賦值會報錯。

總結:

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

總之,在代碼塊內,使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時性死區”。(簡稱TDZ)

4.總結

let和var最大的區別在於,let會創建一個新的作用域叫塊級作用域,而var只有全局和函數作用域;

除此之外let的使用比var更加嚴格,必須要先定義再使用,且和const一樣在同一作用域內不予許重複定義,否則程序會報錯。

這裡是【IT人一直在路上】,關注我,學習更多前端技術,一起從小白走向高級工程師。

專欄

必須掌握的前端面試題

作者:小劉愛學習

10幣

0人已購

查看


分享到:


相關文章: