国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

深入理解es6塊級(jí)作用域的使用

2019-11-19 11:55:51
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

一.var 聲明與變量提升機(jī)制

在JavaScript中使用var定義一個(gè)變量,無(wú)論是定義在全局作用域函數(shù)函數(shù)的局部作用域中,都會(huì)被提升到其作用域的頂部,這也是JavaScript定義變量的一個(gè)令人困惑的地方。由于es5沒(méi)有像其它類C語(yǔ)言一樣的塊級(jí)作用域,因此es6增加了let定義變量,用來(lái)創(chuàng)建塊級(jí)作用域。

我們來(lái)看一個(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í)作用域中所定義的變量無(wú)法再全局被訪問(wèn)到,塊級(jí)作用域也被稱為詞法作用域。

塊級(jí)作用域存在于兩個(gè)地方:

  1. 函數(shù)內(nèi)部。
  2. 指定代碼塊中。(即"{"和"}"之間的區(qū)域)

1.let 聲明

let聲明同var聲明用法一致,唯一的區(qū)別在于,let聲明將變量限制在一個(gè)塊內(nèi),這樣就形成了一個(gè)塊級(jí)作用域,因此也就不會(huì)存在變量的提升了。

例如前面的示例,我們可以寫(xiě)成如下:

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í)作用域之外是無(wú)法訪問(wèn)到所聲明的變量的。換句話說(shuō),就是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聲明的變量不能被賦值,無(wú)論是在非嚴(yán)格模式下還是在嚴(yán)格模式下,都不能對(duì)const聲明的變量進(jìn)行賦值。如下例:

const name = 'eveningwater';//錯(cuò)誤name = 'loho';

不過(guò),如果定義的是一個(gè)對(duì)象,可以對(duì)對(duì)象的值進(jìn)行修改,如下例:

const student = {  name:'eveningwater'}student.name = 'loho';//沒(méi)問(wèn)題//錯(cuò)誤,相當(dāng)于賦值修改對(duì)象student = {  name:'loho'}

4.臨時(shí)死區(qū)

前面提到let和const聲明的變量都不會(huì)提升到作用域的頂部,因此在使用這兩個(gè)標(biāo)識(shí)符聲明之前訪問(wèn)會(huì)報(bào)錯(cuò),即使是typeof操作符也會(huì)觸發(fā)引用錯(cuò)誤。如下例:

console.log(typeof name);//報(bào)錯(cuò)const name = 'eveningwater';

由于第一行代碼就報(bào)錯(cuò)了,因此后續(xù)的聲明變量語(yǔ)句不會(huì)執(zhí)行,此時(shí)就出現(xiàn)了JavaScript社區(qū)所謂的"臨時(shí)死區(qū)"(temporal dead zone).雖然這里示例是const聲明,但let聲明也是一樣的。

但如果在const或let聲明的變量的作用域之外使用typeof操作符監(jiān)測(cè)卻不會(huì)報(bào)錯(cuò),只不過(guò)會(huì)返回undefined。如下例:

console.log(typeof name);//undefinedif(condition){  let name = 'eveningwater';}

5.循環(huán)中的塊級(jí)作用域綁定

我們?cè)谑褂胿ar聲明變量的時(shí)候,總會(huì)遇到這樣的情況,如下:

for(var i = 0;i < 100;i++){  //執(zhí)行某些操作}//這里也能訪問(wèn)到變量iconsole.log(i);//100

我們可以使用let聲明將變量i限制在循環(huán)中,此時(shí)再在循環(huán)作用域之外訪問(wè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)于是在全局中訪問(wèn)變量i的值,即i = 5這個(gè)值,因此實(shí)際上答案最終會(huì)返回5次5.

在es5中,我們可以使用函數(shù)表達(dá)式(IIFE)來(lái)解決這個(gè)問(wèn)題,因?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)榍懊嫣岬竭^(guò),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è)語(yǔ)句就是在嘗試修改常量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});//以下也沒(méi)問(wèn)題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});

這里并沒(méi)有修改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è)新的綁定,也就是說(shuō)不會(huì)成為window對(duì)象的屬性。換句話說(shuō),就是所聲明的變量不會(huì)覆蓋全局變量,而只會(huì)遮蔽它。如下例:

let Array = '這是數(shù)組';console.log(Array);//'這是數(shù)組‘;console.log(window.Array);//應(yīng)該返回創(chuàng)建數(shù)組的構(gòu)造函數(shù),即f Array(){}

這也就是說(shuō)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í)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 靖西县| 莎车县| 苍山县| 冷水江市| 博白县| 疏勒县| 石嘴山市| 邯郸市| 卢湾区| 同仁县| 渝中区| 永修县| 手游| 东台市| 集安市| 石门县| 牙克石市| 泗水县| 汉川市| 青河县| 抚松县| 诸城市| 长武县| 彭水| 长治县| 讷河市| 木兰县| 犍为县| 饶河县| 陇南市| 聂荣县| 武宁县| 吉水县| 廊坊市| 芜湖市| 安仁县| 平潭县| 五常市| 布尔津县| 梁山县| 大庆市|