
變量的聲明是每一種程式設計語言中最基礎的部分,在大多數的程式設計語言中,變量總是在聲明的地方建立,然後 JavScript 并不是這樣,變量的實際建立位置取決于你如何聲明它,加上 es6 引入了 let 和 const 便于在開發中更好的控制變量的作用域。同樣這部分知識也是面試中經常遇到的問題。本篇部落格就來記錄一下關于 JavScript 中變量聲明綁定的學習筆記。
var 聲明的變量,如果不在函數内部,則視為全局作用域頂部聲明的變量,若在函數内部,視為目前函數内部的全局變量。如代碼段1:
上面的代碼中,用 var 定義一個全局變量 value,在函數内部也同樣用 var 聲明一個函數内部的全局變量 value ,在 getValue() 的時候,傳回函數内部的 value 變量值 backValue,直接通路 value 變量時通路的是最外層全局的 value 值為 value。在來看下面這段代碼。如代碼段2:
這段代碼和上面代碼段1項比較就是在getValue()方法内部沒用用 var 聲明 value ,此時函數内部通路的是最外層全局的value ,一次執行 getValue() 函數時候,将最外層全局的value值改變成了 backValue,後面正常輸出。接下來再看下面的代碼段3:
這段代碼中,在getValue()方法中通路 value 變量,并傳回其對應的值,但是函數内部作用域并沒有聲明該變量,一次js引擎回幫助我們項上層作用域中選擇,即找到了最外層的全局作用域,之後正常傳回。了解了上面的代碼片段,我們在來看下下面的代碼段4:
這段代碼得出結果不難了解,但是你知道為什麼會是這樣的結果嗎,你知道js引擎在幫我們做了哪些事情嗎?針對上面的代碼段4 ,js引擎會對其代碼的位置進行調整,如下代碼段5:
不難看出,var 聲明的變量在函數内部也會提升,先聲明,初始值為undefined,在else分支内部也可以拿到 value 這個變量。
使用 var 關鍵字聲明的變量,無論其實際聲明位置在何處,都會被視為聲明于所在函數的頂部,如果不在任意函數内,則視為全局作用域的頂部,這就是所謂的變量提升。
使用var 聲明的變量,不在任意函數内部的時候,相當于給全局window 對象添加一個屬性,這導緻使用 var 可能無意間覆寫 window對象的已有屬性。如果你在全局作用域上使用let 或者const 建立新的變量,雖然 全局作用域上會建立新的綁定,但是不會有任何屬性被添加到全局window對象上,這就以為着不能使用let 或者const 來覆寫一個全局變量,隻能将其屏蔽。如下面代碼段6:
es6 引入了let 聲明的塊級作用域,用let 所聲明的變量在指定的作用域外無法通路,塊級作用域的建立方式如下:
a、在函數内部建立
b、在一個代碼塊中建立,比如 if...else...中的花括号内。
仔細閱讀如下代碼段7:
上面的代碼,在if 分支中用let 聲明一個value變量,屬于塊級變量,是以在else 分支中是無法通路的,是以執行else 分支的代碼時,通路value 變量報錯,value is not defined 。同樣在 if...else...結束了判斷後也是無法通路這個變量的。
let 不像 var 一樣,let 不能在同意作用域中重複聲明一個已有辨別。如下代碼段8:
隻要一進入目前作用域,所要使用的變量就已經存在了,但是不可擷取,隻有等到聲明變量的那一行代碼出現,才可以擷取和使用該變量,暫時性死區知識塊級作用域中的一個特殊性質。如下代碼段9:
先來看下下面代碼段10:
for循環中使用 var 聲明一個a 變量,相當于在外層作用域中先聲明一個a變量,值為undefined,然後在每次循環中給 a 指派,并通路 a 的值,但是如果使用 let 聲明一個變量 i ,i隻屬于for 循環的塊級作用域,循環結束後任意位置都不能通路該變量。再次通路就會報錯 。
代碼段11如下:
這段代碼輸出十次10,是因為循環内建立的函數都擁有對同一個變量的引用,循環結束的時候,全局的i變量值為10,是以每次通路 func()這個方法每次都輸出10。在來看下用 let 的時候,代碼段12如下:
使用了let之後,在循環中let聲明的變量,每次都會建立一個新的i變量,是以在循環中建立的函數獲得了各自的 i 的副本,而每個 i 副本都在每次循環疊代聲明變量的時候被确定了。同樣這種方式适用于 for -of ,for -in中,如下代碼段13:
const 和let 一樣,聲明的變量都屬于塊級作用域,是以const具有 let 相同的特性,除此之外,還有一些特性如下:
const在聲明變量初始化的時候必須指派,例如:
如上面的代碼,const聲明對象的時候,對象的值是可以被修改的,const會阻止變量綁定和變量自身值的修改,但是無法阻止變量成員的修改,在 js 中,變量名存在在棧記憶體中,而變量對應的值存儲在堆記憶體中,const隻能阻止由棧記憶體指向堆記憶體的位址不發生改變,但是無法阻止堆中具體的資料發生改變。
上面的代碼中 i 被定義為一個常量,第一次初始化時候指派為 0 ,然後列印出0,之後執行 i++ ,改變 i 的值,文法報錯,這個錯誤容易了解。
但是,const 在 for-of 和 for-in 中使用和 let 效果一樣
(1)塊級作用域
(2)變量提升
(3)暫時性死區
(4)重複聲明
(5)是否屬于window屬性,覆寫問題
以上就是本文的全部内容,希望給讀者帶來些許的幫助和進步,友善的話點個關注,小白的成長之路會持續更新一些工作中常見的問題和技術點。