第二章 let 和const命令

  1. let命令
  2. 塊級(jí)作用域
  3. const命令
  4. 頂層對(duì)象的屬性
  5. globalThis 對(duì)象

可抽取出的面試題

  1. es6中一共有多少聲明變量的方法?例如:var和function
  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

3.關(guān)于塊級(jí)作用域,for循環(huán)有何特殊之處?(提示:父作用域,子作用域)
4.說(shuō)一下變量提升和暫時(shí)性死區(qū)?
從var舉例說(shuō)變量提升,暫時(shí)性死區(qū)用let舉例
5.es6中關(guān)于頂層對(duì)象屬性和全局變量的差異?(var和let舉例 )

1. let命令

es6新增let命令,用來(lái)聲明變量,用法類似于var,但是用let所聲明的變量,只在let所在的代碼塊中有效,代碼塊外引用,為undefined,
使用場(chǎng)景,for循環(huán)中計(jì)數(shù)器特別適合
區(qū)別例子:

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

由于上面代碼中,i是全局變量,在全局范圍內(nèi)有效,所以全局只有一個(gè)變量i,每一次循環(huán),變量i的值都會(huì)發(fā)生改變,而循環(huán)內(nèi)被賦值給a數(shù)組的函數(shù)內(nèi)部的console.log(i)指向的是就是全局的i,所以是最后一輪輸出的i的值,也就是10,
如果使用let聲明,變量?jī)H在代碼塊內(nèi)有效,所以最后輸出的是6。
另外,for循環(huán)有一個(gè)特別的作用域,就是設(shè)置循環(huán)變量的那一部分是一個(gè)父作用域,而循環(huán)內(nèi)部是子作用域,

for(let i=0;i<3;i++){
  let i = 'abc';
  console.log(i);
}

上面代碼運(yùn)行了三次abc,這就說(shuō)明for循環(huán)中,函數(shù)體重的變量i和循環(huán)變量i不在同一個(gè)作用域,有各自單獨(dú)的作用域。

不存在變量提升

var變量會(huì)發(fā)生‘變量提升’現(xiàn)象,即變量可以在聲明之前使用,值為undefined,這種現(xiàn)象多少有點(diǎn)奇怪,按照一般的邏輯,變量應(yīng)該在聲明后才能使用。
為了糾正這種現(xiàn)象,let命令改變了語(yǔ)法行為,它所聲明的變量,一定要在聲明后使用,否則報(bào)錯(cuò),

暫時(shí)性死區(qū)

只要塊級(jí)作用域內(nèi)存在let命令,它所聲明的變量就“綁定”(binding)這個(gè)區(qū)域了,不再受外部影響。

tem  = 123;
if(true){
  tem = 'abc';  //ReferenceError
  let tem;
}

上述代碼,存在全局變量tem,但是塊級(jí)作用域內(nèi)let又聲明了一個(gè)tem這個(gè)時(shí)候,其實(shí)是后者這個(gè)let聲明的tem綁定到了這個(gè)if執(zhí)行體中的跨級(jí)作用域,所以這時(shí)候報(bào)錯(cuò)就變成前面提到的不存在變量提升了,因?yàn)榇藭r(shí)的tem是綁定的let聲明的這個(gè),es6明確規(guī)定:如果代碼塊中存在let和 const命令,這個(gè)區(qū)塊對(duì)這些命令聲明的變量,從一開始就形成了封閉作用域,凡是在聲明前就使用這些變量,就會(huì)報(bào)錯(cuò)。這在語(yǔ)法上,稱為“暫時(shí)性死區(qū)”

不允許重復(fù)聲明

let不允許在相同作用域內(nèi),重復(fù)聲明同一個(gè)變量

塊級(jí)作用域

為什么需要塊級(jí)作用域?

es5只有全局作用域和函數(shù)作用域,沒有塊級(jí)作用域,這帶來(lái)很多不合理的場(chǎng)景。
第一種情景,內(nèi)層變量可能會(huì)覆蓋外層變量。

var tmp = new Date();
function f(){
  console.log(tmp);
  if(false){
    var tmp = 'hello word';  
  }
}
f()//undefined

上面代碼的原意是if代碼塊外的tmp使用外層聲明的,if代碼塊內(nèi)的使用內(nèi)層聲明的變量。但是,函數(shù)f執(zhí)行后,輸出結(jié)果是undefined,原因在于變量提升,導(dǎo)致console使用 的是if代碼塊內(nèi)的,但是if代碼塊并沒有執(zhí)行,所以tmp是undefined。
第二種是for循環(huán)后,計(jì)數(shù)變量沒有及時(shí)回收,一直存在于全局變量中,

塊級(jí)作用域與函數(shù)聲明

函數(shù)能不能在塊級(jí)作用域之中聲明?這是一個(gè)相當(dāng)令人混淆的問(wèn)題。
es5規(guī)定,函數(shù)只能在頂層作用域和函數(shù)作用域中聲明,不能在塊級(jí)作用域中聲明。但是瀏覽器沒有遵守這個(gè)規(guī)定,為了兼容以前的代碼,還是支持在塊級(jí)作用域中聲明函數(shù),ES6 引入了塊級(jí)作用域,明確允許在塊級(jí)作用域之中聲明函數(shù)。ES6 規(guī)定,塊級(jí)作用域之中,函數(shù)聲明語(yǔ)句的行為類似于let,在塊級(jí)作用域之外不可引用。
另外,還有一個(gè)需要注意的地方。ES6 的塊級(jí)作用域必須有大括號(hào),如果沒有大括號(hào),JavaScript 引擎就認(rèn)為不存在塊級(jí)作用域。

3const命令

const是一個(gè)只讀常量,一旦聲明,常量的值不可改變。這意味著const一旦聲明,就必須立刻初始化,不能留到以后賦值,
const的作用域與let相同,只在聲明所在的塊級(jí)作用域內(nèi)有效。
const命令聲明的常量也是不提升,存在暫時(shí)性死區(qū),只能在聲明后使用,在相同作用域內(nèi),也不可重復(fù)聲明

es6聲明變量的六種方法

es5只有兩種聲明變量的方法,var和function,但是在es6中,除了添加了上面我們提到的let和const外,后面章節(jié)還會(huì)提到,兩外兩種聲明變量的方法:import命令和class命令。所以es6一共有6種聲明變量的方法。

4.頂層對(duì)象的屬性

頂層對(duì)象,在瀏覽器中指的是window對(duì)象,在Node中指的是global對(duì)象,es5之中,頂層對(duì)象的屬性和全局變量是等價(jià)的。

window.a = 1;
a // 輸出1
a = 2;
window.a //2

上面代碼中,頂層對(duì)象的屬性與全局變量的賦值,是同一件事。
頂層對(duì)象的屬性與全局變量掛鉤,被認(rèn)為是JavaScript語(yǔ)言最大的設(shè)計(jì)敗筆之一。這樣的設(shè)計(jì)帶來(lái)了幾個(gè)很大的問(wèn)題。
首先是沒法在編譯時(shí)就報(bào)出變量未聲明的錯(cuò)誤,只有在運(yùn)行時(shí)才知道;
其次,程序員很容易不知不覺的就創(chuàng)建了全局變量,最后,頂層對(duì)象的屬性是到處可以讀寫的,這非常不利于模塊化編程。另一方面,window對(duì)象有實(shí)體含義,指的是瀏覽器的窗口對(duì)象,頂層對(duì)象是一個(gè)有實(shí)體含義的對(duì)象,也是不合適的。
es6為了改變這一點(diǎn),一方面規(guī)定,為了保持兼容性,var命令和function命令聲明的全局變量,依舊是頂層對(duì)象的屬性;另一方面規(guī)定,let命令,const命令,class命令聲明的全局變量,不屬于頂層對(duì)象的屬性。也就是說(shuō),從es6開始,全局變量將逐步的與頂層對(duì)象屬性脫鉤。

5. globalThis對(duì)象

JavaScript語(yǔ)言存在一個(gè)頂層對(duì)象,它提供全局環(huán)境(即全局作用域),所有代碼都是在這個(gè)環(huán)境中運(yùn)行。但是,頂層對(duì)象在各種實(shí)現(xiàn)里面是不統(tǒng)一的

  • 瀏覽器中,頂層對(duì)象是window,但Node和web worker沒有window;
  • 瀏覽器和web worker里面,self也指向頂層對(duì)象,但是Node沒有self ;
  • Node里面,頂層對(duì)象是global,但其他環(huán)境不支持。

同一段代碼為了能夠在各種環(huán)境中,都能取到頂層對(duì)象,現(xiàn)在一般是使用this變量,但是有局限性

  • 全局環(huán)境中,this會(huì)返回頂層對(duì)象,但是,Node模塊和es6模塊中,this返回的是當(dāng)前模塊;
  • 函數(shù)里面的this,如果函數(shù)不是作為對(duì)象的方法運(yùn)行,而是單純的作為函數(shù)運(yùn)行,this會(huì)指向頂層對(duì)象。但是,嚴(yán)格模式下,這時(shí)this會(huì)返回undefined。
  • 不管是嚴(yán)格模式,還是普通模式,new Function('return this')(),總是會(huì)返回全局對(duì)象。但是,如果瀏覽器用了 CSP(Content Security Policy,內(nèi)容安全策略),那么eval、new Function這些方法都可能無(wú)法使用。

綜上所述,很難找到一種方法,可以在所有情況下,都取到頂層對(duì)象。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容