一起來(lái)了解JavaScript的變量作用域
1.變量作用域的分析
首先,我們先研究一下JavaScript的變量作用域,研究作用域,我們不按照常規(guī)的文章那樣解釋概念,而是先給一個(gè)小demo,吊一下大家的胃口:
var a = 1; var b = 2; function pomp(){ alert(a); alert(b); b = 2; alert(b); var a = 3; alert(a); } pomp();
如果你的答案是對(duì)的,那么你對(duì)JavaScript的作用域的理解已經(jīng)是中等偏上了,可能有一些復(fù)雜的作用域你沒(méi)有掌握,但是簡(jiǎn)單的開(kāi)發(fā)已經(jīng)沒(méi)有問(wèn)題了;如果你不知道答案,那么下面我就以這個(gè)例子為引,介紹一下JavaScript的變量作用域問(wèn)題。
首先,如果有編程基礎(chǔ)的同學(xué),一定知道對(duì)于任何的編程語(yǔ)言,都有局部變量和全局變量的概念:全局變量的作用范圍是全局的;而局部變量往往在一個(gè)部分被定義和使用,在這個(gè)部分之外,它的空間就會(huì)被回收,我們就無(wú)法再使用它。常見(jiàn)的局部變量出現(xiàn)的地方有:for循環(huán)、函數(shù)體、代碼塊。
在這些“局部”里,局部變量的優(yōu)先級(jí)是大于全局變量的,這是什么意思呢?我們?cè)儆靡粋€(gè)小demo來(lái)解釋一下:
var a = 1 function pomp() { var a = 2 alert(a) } pomp() alert(a)
也就是說(shuō),我們?cè)诰植亢腿侄加幸粋€(gè)變量a,那么在局部,腳本解釋器會(huì)優(yōu)先從最近的位置開(kāi)始尋找,最近的位置,當(dāng)然會(huì)有局部>大于全局的效果,于是第一個(gè)彈窗彈出的是2,第二個(gè)才是1。
介紹完了局部變量和全局變量,我們再回到最開(kāi)始的那個(gè)demo的問(wèn)題:
var a = 1; var b = 2; function pomp(){ alert(a); alert(b); b = 2; alert(b); var a = 3; alert(a); } pomp();
顯然,這里的問(wèn)題是,我們明明已經(jīng)給a聲明為全局變量,并同時(shí)給a賦值了,那為什么會(huì)打印a為undefined呢?這就是JavaScript的另一個(gè)特點(diǎn),就是解釋器在一行一行解釋代碼之前,會(huì)給變量劃好它們的作用域:
最開(kāi)始,a和b都被聲明并定義為全局變量,a有值1,b有值2;此時(shí),我們定義了一個(gè)函數(shù)pomp(),在函數(shù)內(nèi)部,我們又創(chuàng)建了一個(gè)局部變量a,這時(shí)候,按照剛才的分析,此時(shí)離得最近的其實(shí)應(yīng)該是局部變量a,這就解釋了為什么第一次alert(a)不是彈出1,但是還是沒(méi)有解釋undefined。
undefined的原因是這樣的:在解釋器解釋代碼之前,按照其他編程語(yǔ)言的叫法,我們稱這個(gè)時(shí)期是預(yù)編譯時(shí)期,在預(yù)編譯時(shí)期,由于函數(shù)體內(nèi)也聲明和定義了變量a,于是自然地函數(shù)體內(nèi)的a被劃歸到了局部變量a,即我們可以認(rèn)為已經(jīng)執(zhí)行了一句:var a,但是由于這是預(yù)編譯時(shí)期,并沒(méi)有執(zhí)行var a = 3,因此此時(shí)我們可以理解為,只是執(zhí)行了 var a,而a = 3是在后面才會(huì)執(zhí)行,因此這是undefined的原因。
最后針對(duì)第一開(kāi)始的demo做一個(gè)圖片,幫助大家理解JavaScript變量作用域:
并附帶一句總結(jié):
當(dāng)使用var關(guān)鍵字時(shí),在局部或者全局中的任何位置,當(dāng)某個(gè)變量被聲明后,無(wú)論是之前的哪個(gè)地方,都可以使用這個(gè)變量,只是會(huì)顯示undefined。
2.var關(guān)鍵字
最初的JavaScript,只有var這個(gè)關(guān)鍵字,因此上面的作用域講解,說(shuō)白了是針對(duì)的var關(guān)鍵字,那么對(duì)于var關(guān)鍵字,這里就不再多做贅述,而是給一個(gè)小demo理解一下:
alert(a) var a = 3 alert(a)
不過(guò)避免一些朋友從這里才開(kāi)始看起,我還是再?gòu)?fù)述一下:
var關(guān)鍵字聲明的變量,只要在局部/全局的任何一個(gè)地方被聲明,那么在其他的地方,即使沒(méi)有被聲明,由于在預(yù)編譯階段該變量已經(jīng)被聲明,于是它也是存在的,只是會(huì)顯示undefined,也就是未定義,而后當(dāng)執(zhí)行到var a = 3,它被定義了一個(gè)值3。
順便簡(jiǎn)單嘮一下變量的聲明與定義的區(qū)別:
- var a;這句話叫聲明變量a
- a = 3;這句話叫定義變量a
- var a = 3;這句話叫聲明變量a,并給a定義為3
講完了var,其實(shí)作用域的難點(diǎn)也基本上結(jié)束了,但是由于是一篇完整的文章,下面對(duì)兩種新的JavaScript變量聲明關(guān)鍵字進(jìn)行介紹:let和const,它們的作用域與var略有不同。
3.let和const關(guān)鍵字
首先,我們還是先來(lái)一個(gè)demo:
alert(a) let a = 3 alert(a)
哎嘿,大家點(diǎn)擊之后,是不是啥也沒(méi)有啊,這可不是我在惡作劇,而是確實(shí)是什么也沒(méi)有,原因是,它報(bào)錯(cuò)了(hahaha):
好家伙,同樣的寫(xiě)法,為啥var不報(bào)錯(cuò),let就報(bào)錯(cuò)了呢?(注意,這里用const是一樣的,const和let的作用域是相同的,也即用const一樣會(huì)報(bào)錯(cuò)!)
原因是,大家苦var久矣,這個(gè)let關(guān)鍵字,就是更符合我們的思維邏輯的一種變量的聲明方式,在let的作用域中:
一個(gè)變量只會(huì)在它被聲明之后才可以使用,而不是像var一樣,在任何地方只要有聲明,那么在前面的地方也可以用!
最后,我們簡(jiǎn)單介紹一下const,const在let的基礎(chǔ)上,多了一個(gè)唯一性的概念:
const變量一經(jīng)定義,就不能再修改它的值了,適合定義一些特定的常量,例如:
const pi = 3.14
const e = 2.7
const的作用域與let相同!
4.var、let和const的對(duì)比
一口氣看完了三個(gè)關(guān)鍵字,我們最后再簡(jiǎn)單梳理一下吧,在梳理之前,先上一個(gè)demo:
function demo() { for (var i = 1; i < 10; i++) { // } alert(i) for (let j = 1; j < 9; j++) { // } alert(j) } demo()
大家看到這里似乎又有點(diǎn)小疑惑,因?yàn)槲覀冎?strong>for循環(huán)是一個(gè)局部,那么局部的變量i和j,在for循環(huán)的外面,理應(yīng)不存在才對(duì),但是很顯然,我們?nèi)绻藢?duì)了會(huì)發(fā)現(xiàn),彈窗彈出了一個(gè)10,也就是說(shuō)i此時(shí)值仍然保留為10,而j確實(shí)和我們想的一樣,是不存在的,它也確實(shí)報(bào)錯(cuò)了:
那為啥會(huì)出現(xiàn)這種情況呢?原因是var關(guān)鍵字聲明的局部變量,會(huì)在整個(gè)大的局部退出時(shí),才會(huì)回收內(nèi)存,也就是說(shuō)for循環(huán)雖然也是一個(gè)局部,但是這個(gè)局部是屬于function這個(gè)大局部,因此才會(huì)出現(xiàn)仍然存在i,但是let顯然又一次達(dá)到了我們的預(yù)期!
關(guān)鍵字 | 作用域 | 值的特點(diǎn) |
var | 變量在局部/全局任何地方被聲明,在對(duì)應(yīng)的局部/全局的其他任何地方都可以直接使用(甚至在聲明之前使用),但是使用時(shí)若未定義,則出現(xiàn)undefined。 | 可以反復(fù)修改 |
let | 變量只能在被聲明語(yǔ)句的后面才可以使用。 | 可以反復(fù)修改 |
const | 變量只能在被聲明語(yǔ)句的后面才可以使用。 | 不可修改 |
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
js如何刪除對(duì)象/數(shù)組中null、undefined、空對(duì)象及空數(shù)組實(shí)例代碼
JS中數(shù)組是我們較為常用的一種數(shù)據(jù)結(jié)構(gòu),下面這篇文章主要給大家介紹了關(guān)于js如何刪除對(duì)象/數(shù)組中null、undefined、空對(duì)象及空數(shù)組的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Axios設(shè)置token請(qǐng)求頭的三種方式
用戶登錄時(shí),后端會(huì)返回一個(gè)token,并且保存到瀏覽器的localstorage中,可以根據(jù)localstorage中的token判斷用戶是否登錄,所以當(dāng)發(fā)送請(qǐng)求時(shí),都要攜帶token給后端進(jìn)行判斷,本文給大家介紹了Axios設(shè)置token請(qǐng)求頭的三種方式,需要的朋友可以參考下2024-02-02JS實(shí)現(xiàn)iframe自適應(yīng)高度的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)iframe自適應(yīng)高度的方法,結(jié)合實(shí)例形式分析了JS實(shí)現(xiàn)iframe高度自適應(yīng)的實(shí)現(xiàn)技巧,并給出了項(xiàng)目示例供大家參考,需要的朋友可以參考下2017-01-01JS使用setInterval實(shí)現(xiàn)的簡(jiǎn)單計(jì)時(shí)器功能示例
這篇文章主要介紹了JS使用setInterval實(shí)現(xiàn)的簡(jiǎn)單計(jì)時(shí)器功能,涉及javascript基于setInterval的定時(shí)觸發(fā)與數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-04-04js簡(jiǎn)單實(shí)現(xiàn)網(wǎng)頁(yè)換膚功能
這篇文章主要為大家詳細(xì)介紹了js簡(jiǎn)單實(shí)現(xiàn)網(wǎng)頁(yè)換膚功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04