您好,登錄后才能下訂單哦!
一.var 聲明與變量提升機(jī)制
在JavaScript中使用var定義一個(gè)變量,無論是定義在全局作用域函數(shù)函數(shù)的局部作用域中,都會(huì)被提升到其作用域的頂部,這也是JavaScript定義變量的一個(gè)令人困惑的地方。由于es5沒有像其它類C語言一樣的塊級(jí)作用域,因此es6增加了let定義變量,用來創(chuàng)建塊級(jí)作用域。
我們來看一個(gè)var定義變量的示例:
function setName(){ if(condition){ var name = 'loho'; console.log(name); }else{ console.log(name); } } var student = 'eveningwater'; setName();
以上代碼可以理解成如下:
var student; function setName(){ var name; if(condition){ name = 'loho'; console.log(name);//loho }else{ console.log(name);//undefined } } student = 'eveningwater'; setName();
二.塊級(jí)聲明
塊級(jí)聲明意在指定一個(gè)塊級(jí)作用域,使得塊級(jí)作用域中所定義的變量無法再全局被訪問到,塊級(jí)作用域也被稱為詞法作用域。
塊級(jí)作用域存在于兩個(gè)地方:
1.let 聲明
let聲明同var聲明用法一致,唯一的區(qū)別在于,let聲明將變量限制在一個(gè)塊內(nèi),這樣就形成了一個(gè)塊級(jí)作用域,因此也就不會(huì)存在變量的提升了。
例如前面的示例,我們可以寫成如下:
let stundent = 'eveningwater'; function setName(){ if(condition){ let name = 'loho'; console.log(name);//loho }else{ //如果條件為false執(zhí)行到這里 console.log(name);//不返回值 } } setName();
2.禁止重聲明
在使用let定義變量之前如果已經(jīng)聲明了相同的變量,就會(huì)報(bào)錯(cuò)。因此不能重復(fù)聲明變量。如以下示例:
var name = 'eveningwater'; //報(bào)錯(cuò),重復(fù)聲明 let name = 'loho';
當(dāng)然這兩個(gè)變量必須是在同一個(gè)作用域中,如果是不同作用域中,則不會(huì)報(bào)錯(cuò)。但有可能會(huì)遮蔽第一次聲明的變量。如以下示例:
var name = 'eveningwater'; if(condition){ //不會(huì)報(bào)錯(cuò) let name = 'loho'; }
3.const聲明
使用const標(biāo)識(shí)符所聲明的變量必須要初始化,因此這個(gè)聲明的就是一個(gè)常量。如下例:
const name='eveningwater';//正確 const name;//錯(cuò)誤,未初始化
const聲明同let聲明一樣,也是創(chuàng)建了一個(gè)塊級(jí)作用域,在這個(gè)塊級(jí)作用域之外是無法訪問到所聲明的變量的。換句話說,就是const所聲明的變量不會(huì)有變量提升機(jī)制。如下例:
if(condition){ const name = 'eveningwater'; console.log(name);//'eveningwater' } //錯(cuò)誤 console.log(name);
同樣的const也不能重復(fù)聲明,如下例:
var name = 'eveningwater'; //錯(cuò)誤,不能重復(fù)聲明 const name = 'loho';
但也可以在不同作用域中重復(fù)聲明,如下例:
var name = 'eveningwater'; if(condition){ const name = 'loho'; console.log(name);//loho,屏蔽全局定義的變量 }
盡管const聲明與let聲明有太多相似的地方,但const聲明也有一處與let聲明不同,那就是const聲明的變量不能被賦值,無論是在非嚴(yán)格模式下還是在嚴(yán)格模式下,都不能對(duì)const聲明的變量進(jìn)行賦值。如下例:
const name = 'eveningwater'; //錯(cuò)誤 name = 'loho';
不過,如果定義的是一個(gè)對(duì)象,可以對(duì)對(duì)象的值進(jìn)行修改,如下例:
const student = { name:'eveningwater' } student.name = 'loho';//沒問題 //錯(cuò)誤,相當(dāng)于賦值修改對(duì)象 student = { name:'loho' }
4.臨時(shí)死區(qū)
前面提到let和const聲明的變量都不會(huì)提升到作用域的頂部,因此在使用這兩個(gè)標(biāo)識(shí)符聲明之前訪問會(huì)報(bào)錯(cuò),即使是typeof操作符也會(huì)觸發(fā)引用錯(cuò)誤。如下例:
console.log(typeof name);//報(bào)錯(cuò) const name = 'eveningwater';
由于第一行代碼就報(bào)錯(cuò)了,因此后續(xù)的聲明變量語句不會(huì)執(zhí)行,此時(shí)就出現(xiàn)了JavaScript社區(qū)所謂的"臨時(shí)死區(qū)"(temporal dead zone).雖然這里示例是const聲明,但let聲明也是一樣的。
但如果在const或let聲明的變量的作用域之外使用typeof操作符監(jiān)測(cè)卻不會(huì)報(bào)錯(cuò),只不過會(huì)返回undefined。如下例:
console.log(typeof name);//undefined if(condition){ let name = 'eveningwater'; }
5.循環(huán)中的塊級(jí)作用域綁定
我們?cè)谑褂胿ar聲明變量的時(shí)候,總會(huì)遇到這樣的情況,如下:
for(var i = 0;i < 100;i++){ //執(zhí)行某些操作 } //這里也能訪問到變量i console.log(i);//100
我們可以使用let聲明將變量i限制在循環(huán)中,此時(shí)再在循環(huán)作用域之外訪問變量i就會(huì)報(bào)錯(cuò)了,因?yàn)閘et聲明已經(jīng)為循環(huán)創(chuàng)建了一個(gè)塊級(jí)作用域。如下:
for(let i = 0;i < 100;i++){ //執(zhí)行某些操作 } //報(bào)錯(cuò) console.log(i);
6.循環(huán)中的創(chuàng)建函數(shù)
在使用var聲明變量的循環(huán)中,創(chuàng)建一個(gè)函數(shù)非常的困難,如下例:
var func = []; for(var i = 0;i < 5;i++){ func.push(function(){ console.log(i); }) } func.forEach(function(func){ func(); });
你可能預(yù)期想的是打印從0到5之間,即0,1,2,3,4的數(shù)字,但實(shí)際上答案并不是如此。由于函數(shù)有自己的作用域,因此在向數(shù)組中添加函數(shù)的時(shí)候,實(shí)際上循環(huán)已經(jīng)運(yùn)行完成,因此每次打印變量i的值都相當(dāng)于是在全局中訪問變量i的值,即i = 5這個(gè)值,因此實(shí)際上答案最終會(huì)返回5次5.
在es5中,我們可以使用函數(shù)表達(dá)式(IIFE)來解決這個(gè)問題,因?yàn)楹瘮?shù)表達(dá)式會(huì)創(chuàng)建一個(gè)自己的塊級(jí)作用域。如下:
var func = []; for(var i = 0;i < 5;i++){ (function(i){ func.push(function(){ console.log(i); }) })(i) } func.forEach(function(func){ func();//這就是你想要的答案,輸出0,1,2,3,4 });
但事實(shí)上有了es6的let聲明,我們不必如此麻煩,只需要將var變成let聲明就可以了,如下:
var func = []; for(let i = 0;i < 5;i++){ func.push(function(){ console.log(i); }) } func.forEach(function(func){ func();//輸出0,1,2,3,4 })
但是這里不能使用const聲明,因?yàn)榍懊嫣岬竭^,const聲明并初始化了一個(gè)常量之后是不能被修改的,只能在對(duì)象中被修改值。如以下示例就會(huì)報(bào)錯(cuò):
//在執(zhí)行循環(huán)i++條件的時(shí)候就會(huì)報(bào)錯(cuò) for(const i = 0;i < len;i++){ console.log(i); }
因?yàn)閕++這個(gè)語句就是在嘗試修改常量i的值,因此不能將const聲明用在for循環(huán)中,但可以將const聲明用在for-in或者for-of循環(huán)中。如下:
var func = []; var obj = { name:'eveningwater', age:22 } for(let key in obj){ func.push(function(){ console.log(key) }) } func.forEach(function(func){ func();//name,age }); //以下也沒問題 var func = []; var obj = { name:'eveningwater', age:22 } for(const key in obj){ func.push(function(){ console.log(key) }) } func.forEach(function(func){ func();//name,age });
這里并沒有修改key的值,因此使用const和let聲明都可以,同理for-of循環(huán)也是一樣的道理。for-of循環(huán)是es6的新增的循壞。。
7.全局作用域綁定
let,const聲明與var聲明還有一個(gè)區(qū)別就是三者在全局作用域中的行為。當(dāng)使用var聲明一個(gè)變量時(shí),會(huì)在全局作用域(通常情況下是瀏覽器window對(duì)象)中創(chuàng)建一個(gè)全局屬性,這也就意味著可能會(huì)覆蓋window對(duì)象中已經(jīng)存在的一個(gè)全局變量。如下例:
console.log(window.Array);//應(yīng)該返回創(chuàng)建數(shù)組的構(gòu)造函數(shù),即f Array(){} var Array = '這是數(shù)組'; console.log(window.Array);//返回'這是數(shù)組';
從上例,我們可以知道即使全局作用域中已經(jīng)定義了Array變量或者已經(jīng)存在了Array屬性,但我們之后定義的Array變量則會(huì)覆蓋之前已經(jīng)定義好的或者已經(jīng)存在的Array變量(屬性)。
但是es6的let和const聲明則不會(huì)出現(xiàn)這種情況,let和const聲明會(huì)創(chuàng)建一個(gè)新的綁定,也就是說不會(huì)成為window對(duì)象的屬性。換句話說,就是所聲明的變量不會(huì)覆蓋全局變量,而只會(huì)遮蔽它。如下例:
let Array = '這是數(shù)組'; console.log(Array);//'這是數(shù)組‘; console.log(window.Array);//應(yīng)該返回創(chuàng)建數(shù)組的構(gòu)造函數(shù),即f Array(){}
這也就是說window.Array !== Array這個(gè)等式返回布爾值true。
8.塊級(jí)綁定的最佳實(shí)踐
在使用es6塊級(jí)聲明變量中,最佳實(shí)踐是如果確定后續(xù)不會(huì)改變這個(gè)變量的值,用const聲明,如果確定要改變這個(gè)變量的值,則用let聲明。因?yàn)轭A(yù)料外的變量值的改變時(shí)很多bug出現(xiàn)的源頭。如下示例:
function eveningWater(){}; eveningWater.prototype.name = 'eveningwater'; let ew = new eveningWater(); //定義不能被修改的變量,也就是用于判斷實(shí)例類型的屬性 const _constructor = ew.constructor; //可以改變自定義的名字屬性 let name = ew.name; if(_constructor === eveningWater || _constuctor === Object){ console.log(_constructor); }else{ name = 'loho'; console.log(name) }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。