主頁 > 企業開發 > let關鍵字:加強版的var關鍵字

let關鍵字:加強版的var關鍵字

2021-01-24 18:59:25 企業開發

本文首發于個人網站:let關鍵字:加強版的var關鍵字

你好,今天大叔想和你嘮扯嘮扯 ES6 新增的關鍵字 —— let,再說 let 的具體用法之前,大叔想先和你說說大叔自己對 let 的感受 —— let 其實就是加強版的 var,為啥這么說呢?別急,且聽大叔慢慢道來,

首先,letvar 的作用是一樣一樣滴,都是用來宣告變數,看到這兒,你可能會有個問題啦,既然作用一樣,為啥還要再搞個什么新特性出來?

想要回答這個問題,就要說到 letvar 的不同之處了,比方說 var 宣告的全域變數會自動添加到頂級物件中作為屬性,而 let 就不會,再比方說 var 允許宣告提升或者重復宣告,而 let 就不允許這樣做,當然了,它們之間的不同可不止這些,大叔也只是舉個栗子而已,

如果你沒了解過 ES6 的內容,看到這兒可能有點懵,沒關系啊~ 別往心里去,因為接下來大叔就是要和你嘮扯嘮扯 let 的具體用法,

宣告的全域變數不是頂級物件的屬性

在整明白 letvar 第一點不同之前,大叔要先和你嘮扯嘮扯 var 這個關鍵字的一些用法,為啥?!var 你要是都整不明白的話,你還想整明白 let,那就是一個美麗的扯!

首先,咱們都知道其實宣告一個全域變數,是既可以使用 var 進行宣告,也可以不使用 var 進行宣告的,比方說像下面這段代碼一樣:

var a = 'a'
console.log(a)
b = 'b'
console.log(b)

上面這段代碼不用大叔多扯,想必你也知道列印的結果是個啥 —— 列印 a 和 b 嘛,別急,這才是個開始,咱不點慢慢來不是~

接下來呢,大叔要用 delete 這個運算子來做個騷操作了 —— 先用 delete 洗掉上面的兩個變數 ab,然后呢再分別列印這兩個變數的值,

你尋思一下這個時候應該列印的結果是啥呢?對啦!變數 a 的值會正常輸出 a,但變數 b 會報錯 b is not defined,那為啥又是這樣一個結果吶?

大叔覺得你應該知道 delete 運算子的作用是用來洗掉物件的屬性,但是 delete 是無法洗掉變數的,對啦!你想的沒錯,這就說明上面宣告的 a 是變數但不是物件的屬性,而是 b 是物件的屬性但不是變數,

大叔這話說的有點繞,給你帶入一個場景吧,比如上面這段代碼是在一個 HTML 頁面中定義的 JavaScript 代碼,那 a 就是一個全域變數,b 就是向 window 物件添加了一個屬性,所以,delete 運算子可以洗掉 b,但不能洗掉 a 的原因了,

那也就是說使用 var 關鍵字宣告的是變數,不使用 var 關鍵字宣告的是 window 物件的屬性唄,話嘮叨這兒,大叔還得來個騷操作,咱再看一段代碼:

var a = 'a'
console.log(window.a)

var b = 'b'
console.log(window.b)

這段代碼如果按照上面的結論,列印的結果就應該是 undefined 和 b,但是~ 你真實運行一下這段代碼,就應該知道實際上列印的結果是 a 和 b!

這咋和上面的結論不一樣呢?!是不是又有點懵?哈哈~ 別先急著懵逼,這個問題實際上是 JavaScript 的作者 Brendan Eich 當年在設計 JavaScript 這門語言時的一個小失誤:在全域作用域中宣告的變數同時會被作為屬性添加到頂級物件中,

可能嘮扯到這兒,你會滿屏的吐槽彈幕:這尼瑪誰不知道?!但大叔真正想和你嘮扯的就是這一點,這個小小的失誤,就導致了使用 var 關鍵字宣告的全域變數會污染全域物件的問題

而 ES6 新增的 let 就很好滴彌補了這個問題!也就是說,使用 let 關鍵字宣告的全域變數不會污染全域物件,不信咱可以來試試嘛~ 還是剛才那個場景,在一個 HTML 頁面中定義 JavaScript 代碼,僅僅把 var 改成 let

let a = 'a'
console.log(a)
console.log(window.a)

這段代碼實際的運行結果就是 a 和 undefined,事實證明 let 有效滴解決了 var 的問題,所以你知道為啥 ES6 要新增一個關鍵字來完成和 var 一樣的事兒了吧?!

不允許重復宣告

但是,但可是,可但是~ let 就這么一點點和 var 的區別嗎?答案肯定不是滴,咱們還是先來嘮扯嘮扯 var 關鍵字,使用 var 宣告的變數是允許反復滴重復宣告的,就像下面這段代碼:

var a = 'a'
var a = 'aa'
console.log(a)

這段代碼最終列印的結果是 aa,原因就在于 var 宣告的變數是允許重復宣告的,可能這會兒你又會問了,這我也知道啊,有啥子問題嗎?

問題肯定是有滴,要是沒有大叔花這么多口舌和你在這兒叨逼叨干啥啊~ 大叔還是給你帶入一個場景,比方說你定義了一個 JS 檔案是需要被其他小伙伴匯入使用滴,那你在這個檔案里面宣告的變數在人家那分分鐘被重新宣告了,你內心是個啥感受?

當然了,大叔就是舉個栗子,你也別太當真啦~ 總而言之,就是說咱們在真實開發時對變數的命名肯定是有規劃的,不能隨意就被重新宣告使用,這樣會讓命名空間很亂很亂滴,

你可能有想問了,這個問題要怎么解決呢?答案其實很簡單,就是使用 ES6 新增的這個 let 關鍵字,因為 let 關鍵字宣告的變數是不允許被重復宣告,否則會報錯滴,不信你也可以看看嘛:

let a = 'a'
let a = 'aa'
console.log(a)

僅僅只是把 var 改成 let,這個結果就是報錯了,報錯的內容是:SyntaxError: Identifier 'a' has already been declared,大概的意思就是變數 a 已經被宣告過了,

所以,你看,let 可不是僅僅那么一點點的區別呢!

不允許宣告提前

這會兒你是不是又想問 letvar 之間還有沒有其他區別啊?大叔也不藏著掖著了,干脆一口氣都和你說了吧!你知道使用 var 關鍵字宣告的變數是允許宣告提前的嗎?啥?不知道!沒事兒,這個簡單,啥叫宣告提前,來看段代碼:

console.log(a)
var a = 'a'

你運行一下這段代碼,看看列印的結果是啥?沒錯~ 結果就是 undefined,為啥不是報錯呢?原因就是使用 var 關鍵字宣告的變數允許宣告提前,還是說人話吧,也就是說,上面這段代碼和下面這段代碼本質上是沒區別的:

var a
console.log(a)
a = 'a'

這樣嬸兒寫你可能就明白了為啥列印的結果是 undefined 而不是報錯了吧!但是,嘿嘿~ 咱們又得嘮扯嘮扯 let 了,因為 let 宣告的變數就不允許宣告提前,不信的話還是給你看段代碼先:

console.log(a)
let a = 'a'

這段代碼運行之后列印的結果就是報錯,報錯的內容是:ReferenceError: Cannot access 'c' before initialization,大概的意思就是無法在宣告變數 c 之前訪問變數 c

暫時性死區(TDZ)

let 是不是挺屌的吧?!那你想不想知道 let 宣告的變數又為啥不允許宣告提前呢?嘿嘿~ 這是因為使用 let 宣告變數的程序中存在一個叫做暫時性死區(Temporal dead zone,簡稱 TDZ)的概念,

是不是覺得挺高深的?哈哈~ 其實沒啥高深的,大叔就給你嘮扯明白這個事兒,規矩不變,咱還是先看段代碼再說:

if (true) {
  console.log(a)

  let a;

  console.log(a)
  a = "a";
  console.log(a)
}

大叔想先問問你這段代碼里面三處列印的結果分別是啥?你得認真的尋思尋思哈~ 這可都是大叔剛和你嘮過的內容,

  • 第一處列印的結果是報錯,報錯內容就是 ReferenceError: Cannot access 'c' before initialization
  • 第二處列印的結果是 undefined
  • 第三處列印的結果是 b

對于這樣的結果,大叔估計你應該會明白,畢竟都是剛嘮過的內容,接下來,你得認真的看了,因為大叔要和你來嘮扯有關暫時性死區的概念了~

所謂的暫時性死區,就是說使用 let 關鍵字宣告的變數直到執行定義陳述句時才會被初始化,也就是說,從代碼從頂部開始執行直到變數的定義陳述句執行,這個程序中這個變數都是不能被訪問的,而這個程序就被叫做暫時性死區,

具體到上面這段代碼的話,實際上暫時性死區的開始和結束位置就像下面這段代碼標注的一樣嬸兒:

if (true) {
  // 暫時性死區開始
  console.log(a); // 報錯,ReferenceError: Cannot access 'a' before initialization

  let a;
  // 暫時性死區結束

  console.log(a); // 輸出undefined
  a = "a";
  console.log(a); // 輸出a
}

撈到這會兒,大叔相信你應該可以明白啥子是暫時性死區了,其實啊,一些新的概念也沒啥難理解的,主要是你理解的角度和方式的問題,

typeof 運算子也不再安全

總體上來說,let 關鍵字要比 var 關鍵字嚴格了許多,導致我們開發時遇到的問題相應會減少許多,但 let 就沒有任何問題了嗎?答案顯然不是滴,大叔一直信奉一句話:任何技術都沒有最優,只有最適合,

ES6 新增的 let 關鍵字也是如此,就比方說剛才咱們撈的暫時性死區的內容,其實就有問題,啥問題呢?你還記得 JS 里面有個運算子叫做 typeof 吧,就是用來判斷原始資料型別的,這個運算子在 let 出現之前相對是比較安全的,說白了就是不容易報錯,但在 let 出現之后就不一定了,比方說如果你把它用在剛才說的暫時性死區里面,它就會報錯了:

if (true) {
  console.log(typeof c)
  let c;
}

這段代碼最終列印的結果同樣是報錯,報錯內容同樣是:ReferenceError: Cannot access 'c' before initialization

塊級作用域

關于 let 關鍵字咱們撈到這會兒,其實基本上已經嘮完了,但是,但可是,可但是~ 嘿嘿~ let 還有一個最重要的特性大叔還沒和你嘮呢,這重量級的都得最后出場不是?!

那這個最重要的特性就是啥呢?叫做塊級作用域,嘮到作用域想必你應該知道在 ES5 中存在兩個:全域作用域和函式作用域,但在 ES6 中又新增了一個塊級作用域,

為什么需要塊級作用域

想嘮明白什么是塊級作用域,咱就得從為啥需要塊級作用域嘮起啊~ 規矩不變,還是先看段代碼:

var a = "a"
function fn() {
  console.log(a)
  if (false) {
    var a = "b"
  }
}
fn()

你覺得這段代碼運行之后列印的結果應該是啥?是 a?是 b?還是... ...?其實結果是 undefined,當然了,這個結果不難得出,你運行一下就能看到,關鍵在于,為啥是這么個結果?!

因為就在于 ES5 只有全域作用域和函式作用域,而上面這段代碼的結果產生的原因就在于區域變數覆寫了全域變數,當然了,還有比這更麻煩的問題呢,比方說咱們再看下面這段代碼:

for (var i = 0; i < 5; i++) {
  console.log("回圈內:" + i)
}
console.log("回圈外:" + i)

是不是無比地熟悉吧?!不就是個 for 回圈嘛!關鍵在哪?關鍵在于 for 回圈結束之后,你會發現依舊能訪問到變數 i,這說明啥?說明變數 i 現在是一個全域變數,當然了,你可能會說這沒啥問題,畢竟之前一直不都是這個樣子的嘛,

什么是塊級作用域

但是,大叔要和你說的是,現在不一樣了啊,現在有塊級作用域啦!啥是塊級作用域?還是看段代碼先:

if (true) {
  let b = "b"
}
console.log(b)

這段代碼運行之后列印的結果是報錯,報錯的內容是:SyntaxError: Lexical declaration cannot appear in a single-statement context

這說明啥?這就說明現在你使用 let 宣告的變數在全域作用域中訪問不到了,原因就是因為使用 let 宣告的變數具有塊級作用域,

接下來你的問題可能就是這個塊級作用域在哪呢吧?其實這個塊級作用域就是在花括號({})里面,比方說,咱們現在把上面那個 for 回圈的代碼用 let 改造一下再看看:

for (let i = 0; i < 5; i++) {
  console.log("回圈內:" + i)
}
console.log("回圈外:" + i)

改造完的這段代碼運行之后的結果就是在回圈結束后的列印結果是報錯,報錯內容大叔就不說了,因為都一個樣,

塊級作用域的注意事項

整明白了啥是塊級作用域,接下來大叔就得和你嘮叨嘮叨需要注意的事兒了,就是在使用 let 關鍵字宣告塊級作用域的變數時可必須在這對 {} 里面啊,不然同樣也會報錯滴,

比方說,咱們經常在使用 if 陳述句時愛把 {} 省略,但是如果 if 陳述句里面是使用 let 宣告變數的話就不行了,不信來看段代碼吧:

if (true) let c = 'c'

這段代碼的運行結果同樣是報錯,而且報錯內容都是一樣的,可是不能忘記哦~

塊級作用域的作用

好了,整明白啥是塊級作用域了,也嘮清楚需要注意的了,你是不是想問問這塊級作用域有啥子用處啊?大叔都想你心里面去了,嘿嘿~

你知道匿名自調函式吧?還記得怎么寫一個匿名自調函式嗎?是不是這樣嬸兒的:

(function(){
  var msg = 'this is IIFE.'
  console.log(msg)
})()

還記得匿名自調函式的作用不?是不是就是為了定義的變數和函式不污染全域命名空間?!有了 let,有了塊級作用域,上面這段匿名自調函式就可以寫成這樣嬸兒的:

{
  let msg = 'this is IIFE.'
  console.log(msg)
}

簡化了不少吧?!

寫在最后的話

好了,整到這兒,ES6 新增的 let 關鍵字所有大叔想和你嘮扯的內容都嘮扯完了,也希望能對你有所幫助,最后再說一句:我是不想成熟的大叔,為前端學習不再枯燥、困難和迷茫而努力,你覺得這樣學習前端技術有趣嗎?有什么感受、想法,和好的建議可以在下面給大叔留言哦~

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/251580.html

標籤:其他

上一篇:uni-app開發經驗分享二十一: 圖片滑動解鎖插件制作決議

下一篇:Centos7上搭建nginx來部署靜態網頁

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more