一、沒有聲明提升 var有聲明提升。 用let來聲明變數時,不會將聲明提升到最頂部。 因此,當我們使用let來聲明變數時,一定要 先聲明再使用 。 註意: let聲明的變數不會被掛載到window對象上。 二、塊級作用域 var不存在塊級作用域,只有全局作用域和函數作用域。 ES6中存在 塊級作用域 ...
一、沒有聲明提升
var有聲明提升。
用let來聲明變數時,不會將聲明提升到最頂部。
console.log(val); // 0
var val = 0;
console.log(a); // Cannot access 'a' before initialization
let a = 1;
因此,當我們使用let來聲明變數時,一定要先聲明再使用。
註意: let聲明的變數不會被掛載到window對象上。
let a = 1;
console.log(a); // 1
console.log(window.a); // undefined
二、塊級作用域
var不存在塊級作用域,只有全局作用域和函數作用域。
ES6中存在塊級作用域,let僅在代碼塊內有效。(用大括弧括起來的區域就是代碼塊,引擎會自動識別它。)
{
var val = 0;
let a = 1;
console.log(a); // 1 (在內部可以被訪問到)
}
console.log(val); // 0
console.log(a); // ReferenceError: a is not defined (到了外部就不存在了)
這和立即執行函數有異曲同工之妙,達到了保護私有變數,防止污染全局的作用。
(function() {
var a = 1;
console.log(a); // 1
})();
console.log(a); // ReferenceError: a is not defined
三、暫時性死區(temporal dead zone)
在使用let的代碼塊中的變數會綁定在當前的塊級作用域中,不受外部作用域干擾。
let a = 0;
{
console.log(a);
let a = 10;
}
在變數用let聲明之前都是不可以用的。(let沒有聲明提升)
這種語法就叫做暫時性死區。
簡而言之,塊級作用域內用let聲明的變數不可以在聲明之前使用。
四、不允許重覆聲明變數
var可以聲明多次。
在同一作用域中,let只能聲明一次。
let a = 1;
let a = 5;
console.log(a); // SyntaxError: Identifier 'a' has already been declared
五、for迴圈計數器
一個問題
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
運行一下結果是10個10。為什麼呢?
第一,var聲明的i可以在全局訪問到,因此可能會出現覆蓋現象。
第二,for迴圈內的計數器是非同步執行的。
綜合以上兩點,1秒後執行10個setTimeout函數,因為i是定義在全局作用域上的,因此,變數i早就被覆蓋成了10。
於是列印出10個10。
解決方案一:立即執行函數
解決問題之前,我們分析到問題的關鍵是i作為全局變數被污染(覆蓋),這才導致了結果出現誤差。
那麼解決這種問題,我們首先想到的就是立即執行函數(IIFE)。
立即執行函數也叫自執行函數,它的作用就是封裝私有變數,防止全局變數受污染。
for(var i = 0; i < 10; i++) {
(function(j){
setTimeout(function() {
console.log(j);
}, 1000);
})(i);
}
解決方案二:let
因為let只在代碼塊內有效,因此使用let就避免了變數污染的問題。
for(let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}