詳細解析let和const命令
let命令
基本用法
我們都知道let命令是用來聲明變量的,類似于var,但是通過let命令聲明的變量只在所在代碼塊內(nèi)有效。
let a = []; for (let i = 0;i < 10; i++ ) { a[i] = function () { console.log(i); } } a[5](); // 5
如上代碼所示,使用的是let聲明的i,那么這個變量僅在塊級作用域內(nèi)有效,即只在每輪循環(huán)內(nèi)有效,所以每次循環(huán)的i其實都是一個新變量,所以最后輸出了5。
如果使用了var去申明i,那么這個i是在全局范圍內(nèi)都有效的,函數(shù)數(shù)組里的i都會指向同一個i,導(dǎo)出最后輸出的是最后一輪循環(huán)的i的值。
那就有了一個疑問,使用let聲明的i如果每一輪都是一個新變量,那怎么知道上一輪循環(huán)的值然后計算出本輪的值?
這是因為JavaScript引擎內(nèi)部會記住上一輪循環(huán)的值,初始化當(dāng)次循環(huán)的i時,會在上一輪循環(huán)的基礎(chǔ)上計算。
for循環(huán)還有一個特別的地方,就是設(shè)置循環(huán)變量的括號內(nèi)是一個父作用域,而循環(huán)體內(nèi)是一個單獨的子作用域。
特性
不存在變量提升:
不存在變量提升我們應(yīng)該都知道,在var命令中會發(fā)生“變量提升”,就是變量可以在聲明之前使用,而值是undefined。這種是比較奇怪的現(xiàn)象,因為他都還沒聲明怎么就可以使用呢?
所以。let命令改變了這種語法,通過let聲明的變量一定要在變量聲明后才能用,不然就會報錯。
console.log(b) // undefined console.log(a) // 報錯ReferenceError let a = 2; var b = 1;
暫時性死區(qū)
只要塊級作用域內(nèi)存在Let命令,那么這個let聲明的變量就綁定了這個區(qū)域,不會受到外部的影響。
var num = 1; if(true) { num = 2; // 報錯,ReferenceError let num; }
如上面代碼所示,if代碼塊內(nèi)想要修改的是if外部的num,但是if內(nèi)部通過let聲明了一個num但為賦值,所以導(dǎo)致了通過let聲明的num綁定了這個塊級作用域(即if內(nèi)部這個塊級作用域),所以不會受到外部的num影響,所以對num賦值會報錯。
ES6明確規(guī)定了,如果在區(qū)塊內(nèi)存在let和const命令,那么這個區(qū)塊對這些命令聲明的變量從一開始就形成封閉的作用域,只要在聲明之前就使用這些變量,就會報做。也稱暫時性死區(qū)(temporal dead zone,簡稱TDZ)
當(dāng)然,這也造成了typeof變得不安全了,因為如果一個變量沒有聲明就使用typeof不會報錯,會返回一個undefined,但是現(xiàn)在不成立了,因為會報錯ReferenceError。
function bar(x = y, y = 2) { return[x,y] } bar() // 報錯
如上代碼所示,調(diào)用bar函數(shù)會報錯,因為參數(shù)x的默認值等于另一個參數(shù)y,但是x在聲明的時候y還沒有聲明,屬于死區(qū)
。
總之,只要進入當(dāng)前作用域,所要使用的變量就已經(jīng)存在,但是不可獲取,只有等到聲明變量的那一行代碼出現(xiàn),才可以獲取和使用該變量。
其實let和const是存在變量提升的,但是由于暫時性死區(qū)的關(guān)系,變量已經(jīng)存在了,但是不可獲取,要等到聲明變量的時候才可以獲取和使用。
不允許重復(fù)聲明
let不允許在校內(nèi)共同作用域內(nèi)重復(fù)聲明同一個變量,這個就不用說了大家都知道。
let a = 1; let a = 2; // 報錯
const
我們都知道const聲明一個只讀的常量。修改這個值就會報錯。但是實際上保證的不是變量的值不能改動,而是變量指向的那個內(nèi)存地址不能改動。
對于簡單數(shù)據(jù)類型來說,值就是保存在變量指向的內(nèi)存地址中,因此等同于常量。
而對于復(fù)合類型的數(shù)據(jù),變量指向的內(nèi)存地址保存的是一個指針,const只保證指針是固定,不保證內(nèi)部的結(jié)構(gòu)是不是可變的。
// 給對象添加一個屬性 const foo = {} foo.name = 123 console.log(foo.name) // 123 // 將foo指向另一個對象,就會報錯 foo = {} // 報錯。
如果想要將對象凍結(jié),可以使用Object.freeze
const foo = Object.freeze({});
特性
- 只在聲明所在的塊級作用域內(nèi)有效。
- const聲明的常量不會提升,同樣存在暫時性死區(qū),只能在聲明后使用。
- 不可重復(fù)聲明。
補充——塊級作用域
函數(shù)能不能在塊級作用域中聲明呢?
ES5中是規(guī)定函數(shù)只能在頂級作用域和函數(shù)作用域之中聲明,不能在塊級作用域聲明。
ES6中引入了塊級作用域,明確允許在塊級作用域之中聲明函數(shù)。而且。函數(shù)聲明的語句的行為類似于let,在塊級作用域之外不可引用。
function f() { console.log('I am outside!') } (function() { if(false) { function f() { console.log('I am inside') } } } f(); }())
上面的代碼,在es5中運行時會得到I am inside!
,因為if內(nèi)部的f函數(shù)會被提升到函數(shù)頭部。
但是在ES6環(huán)境則會報錯,為什么呢?
因為游覽器的實現(xiàn)有自己的方式:
- 允許在塊級作用域內(nèi)聲明函數(shù)
- 函數(shù)聲明類似于var,會提升到全局作用域或函數(shù)作用域的頭部
- 函數(shù)聲明還會提升到所在的塊級作用域的頭部
所以上述代碼實際在ES6的游覽器中會生成這樣的代碼:
function f() { console.log("I am outside!"); } (function () { var f = undefined; if (false) { function f() { console.log("I am inside"); } } })();
因此,應(yīng)該避免在塊級作用域內(nèi)聲明函數(shù),如果確定需要寫成函數(shù)表達式的形式,而不是函數(shù)聲明語句。
到此這篇關(guān)于詳細解析let和const命令的文章就介紹到這了,更多相關(guān)let和const內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JS變量中有var定義和無var定義的區(qū)別以及es6中l(wèi)et命令和const命令
- javascript?變量聲明?var,let,const?的區(qū)別
- JavaScript?ES6語法中l(wèi)et,const?,var?的區(qū)別
- javascript的var與let,const之間的區(qū)別詳解
- JavaScript中ES6規(guī)范中l(wèi)et和const的用法和區(qū)別
- 詳解javascript中var與ES6規(guī)范中l(wèi)et、const區(qū)別與用法
- 5分鐘快速掌握JS中var、let和const的異同
- JavaScript中const、var和let區(qū)別淺析
相關(guān)文章
Javascript中Cookie的獲取和保存應(yīng)用案例
這篇文章主要給大家介紹了關(guān)于Javascript中Cookie的獲取和保存應(yīng)用的相關(guān)資料,Cookie是直接存儲在瀏覽器中的一小串?dāng)?shù)據(jù),文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-09-09JavaScript中自帶的 reduce()方法使用示例詳解
下文小編給大家?guī)砹薺s中自帶的reduce()方法使用示例詳解,非常不錯,具有參考借鑒價值,感興趣的朋友一起學(xué)習(xí)吧2016-08-08一文吃透JS樹狀結(jié)構(gòu)的數(shù)據(jù)處理(增刪改查)
在開發(fā)后臺管理系統(tǒng)時,常常會涉及到各種樹狀結(jié)構(gòu)的數(shù)據(jù)處理邏輯,例如:增,刪,改,查等。而樹狀結(jié)構(gòu)的處理就沒有數(shù)組那么的直觀。本文為大家總結(jié)了JS樹狀結(jié)構(gòu)的數(shù)據(jù)處理的方法,需要的可以參考下2022-07-07在DWR中實現(xiàn)直接獲取一個JAVA類的返回值的兩種方法
本文主要介紹了在DWR中實現(xiàn)直接獲取一個JAVA類的返回值的兩種方法,具有一定的參考價值,下面跟著小編一起來看下吧2016-12-12