var聲明及變量提升(Hoisting)機制
function getValue(){
if(condition){
var value="blue";
//其他代碼
return value;
}else{
//此處可訪問變量value,其值為undefined
return null;
}
//此處可訪問變量value,其值為undefined
}
在函數(shù)作用域通過var聲明的變量,無論在哪里聲明都會被當(dāng)成作用域頂部聲明的變量,但是初引入塊級始化操作依然在原處執(zhí)行。對此,有些開發(fā)者不習(xí)慣則會以為是bug,為此,ECMAScript6引入塊級作用域來強化對變量聲明周期的控制。
塊級聲明
塊級作用域用于聲明 在指定塊的作用域之外無法聲明的變量。
let聲明
function getValue(){
if(condition){
let value="blue";
//其他代碼
return value;
}else{
//此處value不存在
return null;
}
//此處value不存在
}
變量使用let聲明后,不再被提升到函數(shù)頂部,執(zhí)行流離開if塊,value立即被銷毀。
禁止重聲明
var count=30;
//拋出語法錯誤
let count=40;
同一作用域內(nèi)不能用let聲明已聲明過的變量,但是不同作用域可以聲明。
var count=30;
if(condition){
//不會拋出錯誤
let count=40;
//更多代碼
}
const聲明
ECMAscript6標(biāo)準(zhǔn)還提供了const關(guān)鍵字。使用const聲明的是常量,其值一旦被設(shè)定就不可更改,使用每個常量必須初始化。
//有效的常量
const maxItems=30;
//語法錯誤;常量為初始化
const name;
這里聲明的name沒有初始化,所以會拋出語法錯誤。
const和let
const和let都是塊級標(biāo)識符,所以常量也只在當(dāng)前代碼塊有效,一旦執(zhí)行到快外就會被立即銷毀。常量同樣不會被提升到頂部。
if(condition){
const maxItems=5;
//更多代碼
}
//此處無法訪問maxItems
與let相似,在同一作用域用const聲明已存在的標(biāo)識符也會導(dǎo)致語法錯誤。
var message-"Hello";
let age=25;
//這兩條語句都會報錯
const message="Goodbye";
const age=30;
盡管相似之處很多,但const和let聲明有很大的一處不同,const常量不可以再賦值。
const age=25;
//這語句都會報錯
age=30;
但是如果const聲明的是對象,則對象中的值可以修改。
用const聲明對象
const不允許修改綁定,但允許修改值。
const person={
name:"ccg"
};
//可以修改對象中屬性的值
person.name="yeshi";
//拋出語法錯誤
person={
name:"cc"
};
臨時死區(qū)
JavaScript引擎在掃描代碼發(fā)現(xiàn)聲明時,要么將它們提升至作用域頂部(遇見var聲明),要么將聲明放到TDZ中(遇到let和const聲明時),只有執(zhí)行過變量聲明語句后,變量才會從TDZ中移出,然后才可以訪問。
console.log(typeof value);//undefined,value處于TDZ中
if(condition){
let value="blue";//從TDZ移出
console.log(typeof value);//srting
}
循環(huán)中的塊作用域綁定
使用let可以把計數(shù)器變量限制在循環(huán)內(nèi)部。
for (var i = 0; i <10; i++){
process(items[i]);
}
//在這里仍然可以訪問i
console.log(i);
for (let i = 0; i <10; i++){
process(items[i]);
}
//在這里不可以訪問i
console.log(i);
循環(huán)中的函數(shù)
let聲明每次迭代都會創(chuàng)建一個新變量,并以之前迭代的同名變量的值將其初始化。
var funcs=[];
for(let i=0;i<10;i++){
funcs.push(function(){
console.log(i);
});
}
funcs.forEach(function(func){
func();//0,1,2,3,4,5,6,7,8,9
})
對于for-in,for-of循環(huán)也一樣
var funcs=[],
object={
a:true,
b:true,
c:true
};
for(let key in object){
funcs.push(function(){
console.log(key);
});
}
funcs.forEach(function(func){
func();//輸出a、b、c
});
let聲明在循環(huán)內(nèi)部的行為是標(biāo)準(zhǔn)中專門定義的、它不一定與let的不提升特性相關(guān),理解這一點至關(guān)重要。事實上,早期的let不包含這行為,這是后來加入的。
循環(huán)中的const聲明
對于for循環(huán)來說,可以在初始化時使用const,但是不可修改其值。
var funcs=[];
for(const i=0;i<10;i++){
funcs.push(function(){
console.log(i);
});
}//拋出錯誤
對于,for-in和for-of循環(huán),使用const行為和let一致,
var funcs=[],
object={
a:true,
b:true,
c:true
};
for(const key in object){
funcs.push(function(){
console.log(key);
});
}
funcs.forEach(function(func){
func();//輸出a、b、c
});
之所以可以運用在for-in和for-of循環(huán)中,是因為每次迭代不會修改已有綁定,而是會創(chuàng)建一個新的綁定。
全局塊作用域的綁定
let和const與var另外一個區(qū)別就是它們在全局作用域中的行為。var聲明的東西會成為讓全局對象的一個屬性,而let和const并不會。
如果你在全局作用域中使用let或者const,會在全局中創(chuàng)建一個新的綁定,但是該綁定不會添加到全局對象的屬性。
var ccg="ccg";
window.ccg;//ccg
let ccgg="ccgg";
window.ccgg;//undefined
const cgg="cgg";
window.cgg;//undefined
塊級綁定最佳實踐
默認(rèn)使用const,只有確實需要改變變量的值時才使用let,有需要再使用var。因為大部分變量的值的改變都是