日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ES6之let(理解闭包)和const命令

發布時間:2025/7/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ES6之let(理解闭包)和const命令 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ES6之let(理解閉包)和const命令

  最近做項目的過程中,使用到了ES6,因為之前很少接觸,所以使用起來還不夠熟悉。因此購買了阮一峰老師的ES6標準入門,在此感謝阮一峰老師的著作。

  我們知道,ECMAScript 6即ES6是ECMAScript的第五個版本,因為在2015年6月正式發布,所以又成為ECMAScript2015。ES6的主要目的是為了是JS用于編寫復雜的大型應用程序,成為企業級的開發語言。

  說明:由于有時候我們希望得知es6代碼的具體實現原理或者說希望能夠轉化為es5使用,我們可以使用http://babeljs.io/來實現在線將es6代碼轉化為es5代碼。

第一部分:let命令

  一.塊級作用域(重點)。

   我們知道,在javascript中只有全局作用域和函數作用域,并不存在塊級作用域。這樣,在使用時就會出現一些問題。 下面我們先來舉例說明let塊級作用域的使用。

   例1:

  代碼如下所示: 

????????{????????????var?a=5;let?b=10;}console.log(a);console.log(b);

  我們在控制臺得到的結果如下所示:

  也就是說,var聲明的變量由于不存在塊級作用域所以可以在全局環境中調用,而let聲明的變量由于存在塊級作用域所以不能在全局環境中調用。

 

  例2:這個例子是一個非常經典的例子。

  

????????var?a=[];????????for(var?i=0;i<10;i++){a[i]=function(){console.log(i);};}a[6]();?//10

????var?a=[];????for(let?i=0;i<10;i++){a[i]=function(){console.log(i);};}a[6]();????//6

?

  我們可以看到,兩個例子中,唯一的區別是前者for循環中使用var來定義i,得到的結果是10.而后者使用的是let來定義i,最終得到的結果是6.這是為什么呢?阮一峰老師在書中的解釋并不是很清楚,所以下面我會發表個人見解:

  ? 關于這個問題,表面上確實不是很好理解,查詢了很多資料,許多人講到了很多晦澀難懂的知識,似乎很高大上,但是實際上并不難,下面根據我的理解進行解釋,如有問題,歡迎批評指正,如果大家能夠有些收獲就再好不過了。

?

?

  例二前者(var i)具體執行過程如下:

var a=[];


var i=0;//由于var來聲明變量i,所以for循環代碼塊不具備塊級作用域,因此i認為是全局變量,直接放在全局變量中。
a[0]=function(){
? ? console.log(i);//這里之所以i為i而不是0;是因為我們只是定義了該函數,未被調用,所以沒有進入該函數執行環境,i當然不會沿著作用域鏈向上搜索找到i的值。
}// 由于不具備塊級作用域,所以該函數定義就是全局作用域。


var i=1;//第二次循環,這時var i=1;覆蓋了前面的var i=0;即現在i為1;
a[1]=function(){
? ? console.log(i);//解釋同a[0]函數。
}


var i=2;// 第三次循環,這時 i=2,在全局作用域中,所以覆蓋了前面的i=1;
a[2]=function(){
? ? console.log(i);
}


......第四次循環 此時i=3 ?這個以及下面的i不斷的覆蓋前面的i,因為都在全局作用域中
......第五次循環 此時i=4
......第六次循環 此時i=5
......第七次循環 此時i=6
......第八次循環 此時i=7
......第九次循環 此時i=8 ??


var i=9;
a[9]=function(){
? ? console.log(i);
}


var i=10;// 這時i為10,因為不滿足循環條件,所以停止循環

緊接著在全局環境中繼續向下執行。

? ? ? ?a[6]();//這時調用a[6]函數,所以這時隨即進入a[6]函數的執行環境,即a[6]=function(){console.log(i)};執行函數中的代碼 console.log(i); 因為在函數執行環境中不存在變量i,所以此時會沿著作用域鏈向上尋找(可參考我的博文《深入理解作用域和作用域鏈,即進入了全局作用域中尋找變量i,而全局作用域中i=10覆蓋了前面所有的i值,所以說這時i為10,那么a[6]的值就是10了。

  

  說明:對于例如a[1]=function(){console.log(i)};而不是a[1]=function{console.log(1)},可以在控制臺中輸出a[1]函數,即可得到驗證。

?

?

  ? ?例二后者(let i)具體執行過程如下:

?


var a=[];//創建一個數組a;

{ //進入第一次循環
? ? let i=0; //注意:因為使用let使得for循環為塊級作用域,此次let i=0在這個塊級作用域中,而不是在全局環境中。
? ? a[0]=function(){
? ? ? ? console.log(i);
? ? ?}; //注意:由于循環時,let聲明i,所以整個塊是塊級作用域,那么a[0]這個函數就成了一個閉包。
}//?聲明:?我這里用{}表達并不符合語法,只是希望通過它來說明let存在時,這個for循環塊是塊級作用域,而不是全局作用域。

?

講道理,上面這是一個塊級作用域,就像函數作用域一樣,函數執行完畢,其中的變量會被銷毀,但是因為這個代碼塊中存在一個閉包,閉包的作用域鏈中包含著(或著說是引用著)塊級作用域,所以在閉包被調用之前,這個塊級作用域內部的變量不會被銷毀。(更多閉包知識,可以看我的博文《JavaScript之閉包》)


{ //進入第二次循環
? ? ?let i=1; //注意:因為let i=1; 和?上面的let i=0;出在不同的作用域中,所以兩者不會相互影響。
? ? ?a[1]=function(){
? ? ? ? ?console.log(i);
? ? ?}; //同樣,這個a[i]也是一個閉包
}

......進入第三次循環,此時其中let i=2;
......進入第四次循環,此時其中let i=3;
......進入第五次循環,此時其中let i=4;
......進入第六次循環,此時其中let i=5;
......進入第七次循環,此時其中let i=6;
......進入第八次循環,此時其中let i=7;
......進入第九次循環,此時其中let i=8;

{//進入第十次循環
? ? let i=9;
? ? a[i]=function(){
? ? ? ? console.log(i);
? ? };//同樣,這個a[i]也是一個閉包
}

{
? ? let i=10;//不符合條件,不再向下執行。于是這個代碼塊中不存在閉包,let i=10;在這次循環結束之后難逃厄運,隨即被銷毀。
}

a[6]();//調用a[6]()函數,這時執行環境隨即進入下面這個代碼塊中的執行環境:funcion(){console.log(i)};

{?
? ? ?let i=6;?
? ? ?a[6]=function(){
? ? ? ? ? console.log(i);
? ? ?}; //同樣,這個a[i]也是一個閉包
}

? ? a[6]函數(閉包)這個執行環境中,它會首先尋找該執行環境中是否存在 i,沒有找到,就沿著作用域鏈繼續向上到了其所在的代碼塊執行環境,找到了i=6,于是輸出了6,即a[6]();的結果為6。這時,閉包被調用,所以整個代碼塊中的變量i和函數a[6]()被銷毀。

?

相信大家仔細看完上面的函數執行的過程,對let var 塊級作用域 閉包就有一個很好的理解了。我認為重要的是對于函數執行過程的理解!

?

?

  二.不存在變量提升

  這里是說使用let不會像使用var一樣存在一個變量提升的現象。變量提升是什么呢?在沒有接觸es6之前我對此也不清楚,但是我想大家一定都聽說過函數聲明提升:函數聲明來定義函數即可實現函數聲明提升,這樣,我們可以先調用函數,后聲明函數;而函數表達式方法不會實現函數聲明提升,這樣,如果先調用函數,后聲明函數,則會拋出錯誤!!(對于函數聲明提升更多知識可以看我的博文《JavaScript函數之美~》)。? 那么可以以此類推,var定義變量:可以先使用,后聲明;而let定義變量:只可先聲明,后使用。

  例3:

  

????????var?num1=100;console.log(num1);let?num2=200;console.log(num2);console.log(i);????????var?i=10;console.log(j);let?j=5;

    我們可以看到結果如下:

即前兩個都是先聲明后使用,沒有問題。而后兩個都是先使用,后聲明,用var 聲明的顯示undefined,而 let聲明的直接報錯。

說明:console.log(i);

   var i=10;

實際上相當于:

   ?var i;

   ?console.log(i);

   i=10;

所以會出現undefined的情況。

?

 

  三.暫時性死區

  暫時性死區即:只要一進入當前作用域,所要使用的變量就已經存在,但是不可獲取,只有等到聲明變量的那一行代碼出現,才可以獲取和使用該變量。

例5:

?

????var?tmp=123;????if(true){tmp="abc";let?tmp;}

?

? ?結果如下:

也就是說:雖然上面的代碼中存在全局變量tmp,但是塊級作用域內let又聲明了一個局部變量tmp,導致后者綁定了塊級作用域,所以在let聲明變量前,對tmp賦值會報錯。此即暫時性死區。

  

  注意:ES6規定暫時性死區和不存在變量提升就是為了減少運行時的錯誤,防止在變量聲明前就使用這個變量,從而導致意料之外的行為。

?

  四.不允許重復聲明

  

????function?func?(){let?b=100;????????var?b=10;}????function?add(num){let?num;????????return?num+1;}????function?another(){let?a=10;let?a=5;}

上述三個得到的結果均為:

只是前兩者為 b和num被聲明過了。注意:第二個函數,雖然我們沒有明確的聲明,但是參數實際上是相當于用var聲明的局部變量。

?

?

?

第二部分:const命令

?     什么使const命令呢?實際上它也是一種聲明常量的方式。const命令用來聲明常量,一旦聲明,其值就不能改變。初次之外,const和let十分相似。也就是說前者是用于聲明常量的,后者是用于聲明變量的。

?

    1.const聲明常量,一旦聲明,不可改變。

????const?a=10;a=100;

    結果如下

    

    2.既然const一旦聲明不可改變,所以在聲明時必須初始化。

const?a;

     結果如下:

?

    3.const所在的代碼塊為塊級作用域,所以其變量只在塊級作用域內使用或其中的閉包使用。

????if(true){const?a=10;}console.log(a);

    結果如下:

?

    

    4.const聲明的變量不存在變量提升。

????if(true){console.log(a);const?a=10;}

結果如下:

  

?

    5.const不可重復聲明常量。

????var?a=10;const?a=5;

結果如下:

?

?

    6.const命令只是保證了變量名指向的地址不變,并不保證該地址的數據不變。

  

????const?a={};a.name="zzw";console.log(a.name);?const?b=[];b.push("zzw");console.log(b);const?c={};c={name:"zzw"};

  結果如下:

因此,我們使用const所指向的地址不可變,但是地址的內容是可以變得。


轉載于:https://blog.51cto.com/zhanglida66/1921426

總結

以上是生活随笔為你收集整理的ES6之let(理解闭包)和const命令的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。