JavaScript中聲明變量通常使用var
盯串,ES6中引入了let
聲明變量俱饿,這兩者有什么區(qū)別呢?
1. 作用域
- 通過(guò)
var
定義的變量,作用域是整個(gè)封閉函數(shù)熏瞄,是全域的 。 - 通過(guò)
let
定義的變量谬以,作用域是在塊級(jí)或是子塊中巴刻。
function varTest() {
var x = 1;
if (true) {
var x = 2; // 同樣的變量!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // 不同的變量
console.log(x); // 2
}
console.log(x); // 1
}
2. 不可以在當(dāng)前作用域重復(fù)聲明同一個(gè)變量
在同一個(gè)函數(shù)或同一個(gè)作用域中用let
重復(fù)定義一個(gè)變量將引起 TypeError
function letTest() {
let x = 1;
let x = 2;
console.log(x);
}
letTest() // 報(bào)錯(cuò)
3. 變量提升
var
聲明的變量由于存在變量提升(hoist),不論var
聲明的變量處于當(dāng)前作用域的第幾行蛉签,都會(huì)提升到作用域的頭部胡陪。
var a = 1;
function foo(){
alert( a ); // undefined
var a = 2;
}
foo();
瀏覽器在運(yùn)行代碼之前會(huì)進(jìn)行預(yù)解析,首先解析函數(shù)聲明碍舍,定義變量柠座,解析完之后再對(duì)函數(shù)、變量進(jìn)行運(yùn)行片橡、賦值等妈经。
那么
let
存在變量提升么?
let
是存在變量提升的捧书,在JavaScript中吹泡,所有的聲明(var
、function
经瓷、let
爆哑、const
、class
舆吮、function\*
)都會(huì)存在變量提升揭朝,var
聲明的變量與let
聲明的變量區(qū)別在于初始化值的不同。
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
var
聲明的變量會(huì)被提升到作用域的頂部并初始化為undefined
色冀,而let
聲明的變量在作用域的頂部未被初始化潭袱,直到let
聲明的語(yǔ)句被賦值,因此當(dāng)使用這個(gè)值的時(shí)候會(huì)導(dǎo)致一個(gè)reference error
的錯(cuò)誤锋恬,在let
聲明變量之前被稱(chēng)為temporal dead zone
屯换,即臨時(shí)死亡區(qū)。
4. let
與for
循環(huán)配合
for(let i = 0; i < 5 ; i++ ){
setTimeout(function(){
console.log(i) // 0 1 2 3 4
},1000)
}
此時(shí)打印出的結(jié)果為0 1 2 3 4 与学,let
與for
循環(huán)使用時(shí)彤悔,其作用域是(let i = 0; i < 5 ; i++ )
,但是ECMAScript規(guī)定癣防,會(huì)在{}塊級(jí)作用域中定義一個(gè)let j
臨時(shí)變量與(let i = 0; i < 5 ; i++ )
中的i
相等蜗巧,因此setTimeout
中的i
指向不同的i
。
for(var i = 0; i < 5 ; i++ ){
setTimeout(function(){
console.log(i) // 5次5
},1000)
}
而如果換成var
之后蕾盯, 由于i
是函數(shù)級(jí)變量幕屹,5個(gè)內(nèi)部函數(shù)都指向了同一個(gè)i
,而i
最后一次賦值是5蓝丙,因此打印出是5個(gè)5。
參考: