最近在代碼中不當心不規範的,在switch裏面定義了塊級變量,致使頁面在某些瀏覽器中出錯,本文討論如下switch語句中的塊級做用域。git
- switch語句中的塊級做用域
- switch語句中的塊級做用域可能存在的問題
- 規範和檢測
本文的原文在個人博客中,https://github.com/forthealll...github
歡迎startypescript
ES6 或 TS 引入了塊級做用域,經過let和const、class等能夠定義塊級做用域裏的變量,塊級做用域內的變量不存在變量提高,且存在暫時性死區。常見的if語句,for循環的循環體內均可以定義塊級變量。那麼switch語句中的塊級做用域是什麼呢? 先給出結論:瀏覽器
switch語句中的塊級做用域,在整個switch語句中,而不是對於每個case生成一個獨立的塊級做用域。es5
下面來舉幾個例子來講明這個問題:eslint
let number = 1; switch(number){ case 1: let name = 'Jony'; default: console.log(name) }
上述的代碼會輸出jony。調試
再看一個例子:code
let number = 1; switch(number){ case 1: let name = 'Jony'; break; case 2: let name = 'yu'; break; default: console.log(name); }
這樣會在重複生命的錯誤:對象
Uncaught SyntaxError: Identifier 'name' has already been declared
上述兩個例子說明確實switch語句中,整個switch語句構成一個塊級做用域。而與case無關,每個case並不會構成一個獨立的塊級做用域。blog
咱們知道了switch語句,整個switch語句的頂層是一個塊級做用域,可是還要注意case的特殊性,在case中聲明的變量,並不會提高到塊級做用域中。
let number = 2; switch(number){ case 2: name = 'yu'; break; }
在這個例子中,name雖然沒有聲明,可是給name賦值至關於給全局的window對象複製,也就是window.name = 'yu'。不會有任何問題。
有意思的問題來了:
let number = 2; switch(number){ case 1: let name = 'jony'; break; case 2: name = 'yu'; break; }
這個例子中,會報錯,會報name未定義的錯誤。
Uncaught ReferenceError: name is not defined
緣由的話,這裏雖然case裏面定義的塊級雖然不會存在變量提高,可是會存在暫時性死區,也就是說若是let name = 'jony' 沒有執行,也就是name定義的過程沒有執行,那麼name在整個塊級做用域內都是不可用的,都是undefined。
爲了證實咱們的想法,接着改寫上面的例子:
let number = 1; switch(number){ case 1: let name = 'jony'; break; case 2: name = 'yu'; break; }
咱們把number改爲1,咱們發現代碼不會報任何的錯誤,由於此時let name的定義和賦值都被執行了。
可能會說爲何在本身的項目中,在ES6或者TS代碼中即便有上述的錯誤使用,也沒有報錯?
筆者以前也有這樣的問題,要明確的是是否你把ES6或者TS的代碼直接轉化成了es5,而後再調試或者發佈的線上的,當let被編譯成es5後,固然就不會存在上述switch中做用域的問題。可是現實中,編譯成es5後的js文件可能太大,對於高版本瀏覽器咱們但願直接使用ES6代碼(經過type = module來判斷瀏覽器對於ES6的支持性),那麼這麼上述問題就會出現。
那麼如何避免這種狀況呢,固然最好的方式,就是不要在case中定義塊級變量,可是萬一不當心寫了上述的問題代碼如何檢測呢。
首先使用typescript,靜態編譯是不能出現錯誤提示的,由於這個錯誤是運行時異常。最好的方式是經過編寫eslint的規範來解決上述的非法使用問題。