變數宣告帶var與不帶var的區別

admin發表於2018-10-12

JavaScript宣告變數帶var與不帶var區別的問題在網路上基本已經談爛了。

無論是在網上搜尋或者在技術群裡請教,基本都能得到滿滿的回覆。

回覆內容絕大多數如“不帶var宣告的變數的作用域是全域性的,帶var宣告的變數的作用域是當前所在作用域”。

通過程式碼例項驗證一下熱心夥伴們的回覆是否正確:

[JavaScript] 純文字檢視 複製程式碼
function func(){
  address="青島市南區";
  var webName="螞蟻部落";
}
func();
console.log(address);
console.log(webName);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/12/203115ii7b389z93899uv8.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

根據上面理論,address宣告沒有使用var,那麼此變數的作用域是全域性的,而webName宣告使用var,作用範圍是函式作用域,所以在函式外部可以正常列印出address值,列印webName則會報錯,看起來一切都很正確。

現在可以很負責任的告訴大家,上面的結論是錯誤的,只有使用var宣告的才是變數。

看一段程式碼例項:

[JavaScript] 純文字檢視 複製程式碼
console.log(webName);
console.log(address);
var webName;
address;

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201810/12/203146sjp7zzncvieje3oo.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

大家知道,變數宣告有前置現象,如果address也是變數,那麼它一定也會前置。

列印結果會與webName相同,然而事實是報錯了,分析如下:

(1).首先明確一點,在ES規範明確規定只有用var、let或者const宣告的才是變數或者常量。

(2).不使用var建立的address是全域性物件的一個屬性,屬性並沒有前置現象,所以會報錯。

既然webName是變數,那為什麼可以使用window.webName訪問此變數,好像webName也是一個屬性。其實並不是,變數在執行上下文中的變數物件(VO)中儲存,是變數物件的一個屬性,在全域性執行上下文中,全域性物件恰好是變數物件,於是全域性作用域中的變數可以使用全域性物件window訪問。這也是為什麼delete無法刪除使用var宣告的變數,可以刪除不適用var宣告的"變數"的原因(eval執行上下文除外)。

特別說明:除了上下文,其他上下文中無法直接訪問變數物件,因為這是內部的一種實現機制。

很多時候,有些知識點看起來非常簡單,其實在它的後面隱藏比較深層次的一些原理,知曉這些原理之後,很多令人迷惑的奇怪現象會迎刃而解,當然自身也能有一種豁然開朗的快感和極大的成就感。

相關閱讀:

(1).let可以參閱JavaScript let 命令一章節。

(2).變數物件可以參閱JavaScript 變數物件一章節。

(3).delete可以參閱JavaScript delete用法一章節。

相關文章