作用域
變量的作用域無非就是兩種:全局作用域和局部作用域删顶。
全局作用域:
最外層函數(shù)定義的變量擁有全局作用域,即對任何內(nèi)部函數(shù)來說眯漩,都是可以訪問的:
局部作用域:
和全局作用域相反,局部作用域一般只在固定的代碼片段內(nèi)可訪問到,而對于函數(shù)外部是無法訪問的慎宾,最常見的例如函數(shù)內(nèi)部
注意:函數(shù)內(nèi)部聲明變量的時候,一定要使用var浅悉。如果不用的話趟据,你實(shí)際上聲明了一個全局變量,并且會污染同名的全局變量术健。
第一個輸出是undefined汹碱,原本以為它會訪問外部的全局變量(a=”out”),但是并沒有荞估。這可以算是javascript的一個特點(diǎn)比被,只要函數(shù)內(nèi)定義了一個局部變量,函數(shù)在解析的時候都會將這個變量“提前聲明”泼舱。javascript并沒有所謂的塊級作用域等缀,javascript的作用域是相對函數(shù)而言的,所以也可以稱為函數(shù)作用域娇昙。
作用域鏈(Scope Chain)
個人理解就是尺迂,根據(jù)在內(nèi)部函數(shù)可以訪問外部函數(shù)變量的這種機(jī)制,用鏈?zhǔn)讲檎覜Q定哪些數(shù)據(jù)能被內(nèi)部函數(shù)訪問。
舉幾個例子
代碼1
過程分析:
1.聲明變量 a = 123與函數(shù)fn噪裕,(預(yù)解析階段函數(shù)fn提前)蹲盘;
2.將變量a傳遞給fn并執(zhí)行fn,此時函數(shù)內(nèi)a的值變?yōu)?56.
3.向控制臺打印a膳音,結(jié)果為123
過程詳解:
1.全局作用域中的a與局部作用域中的a并非是同一個變量召衔,只不過是他們的變量名稱恰好相同而已,function fn(a){}小括號中的a相當(dāng)于是在fn的局部作用域中聲明了一個變量a祭陷,外部環(huán)境實(shí)際上是無法直接訪問到這個變量的苍凛。
2.在執(zhí)行過程中,fn(a); 中的a是實(shí)參兵志,也就是全局變量a醇蝴,將全局變量a的值123傳遞到函數(shù)fn中,fn的局部變量a接收到這個數(shù) 想罕,然后執(zhí)行a = 456悠栓,那么函數(shù)中的局部變量a的值由123就變?yōu)榱?56。但console.log(a); 是在全局環(huán)境中執(zhí)行的按价,我們之前說過了惭适,全局環(huán)境不能直接訪問局部環(huán)境。所以console.log訪問的仍然是全局變量a楼镐,所以打印值仍然是123癞志。
代碼1加強(qiáng)理解版
變量b的打印結(jié)果為: is not defined ,說明在全局作用域中它不能被訪問到鸠蚪。
代碼1再次加強(qiáng)理解版
全局雖然無法直接訪問局部變量今阳,但局部變量是可以向上訪問它的父級的變量的,此處fn的父級即為全局作用域茅信,所以在fn中console.log(a)時可以拿到a的值盾舌。
代碼2
這段代碼與第一段代碼的不同之處是,標(biāo)紅的fn()小括號中沒有參數(shù)a蘸鲸,也就是說妖谴,此時fn中未對a進(jìn)行聲明我們便在函數(shù)中使用了它,那么此處的a便默認(rèn)是全局變量酌摇,大家會發(fā)現(xiàn)有兩個全局變量a膝舅,函數(shù)的執(zhí)行是在var a =123 之后進(jìn)行的,若有兩個同名全局變量窑多,后執(zhí)行的會覆蓋先執(zhí)行的仍稀。所以兩次打印結(jié)果都是456。
代碼3
var a = 123 和fn(a) 互換了位置埂息,執(zhí)行結(jié)果發(fā)生了變化技潘,此處也反應(yīng)了先后順序?qū)?zhí)行結(jié)果的影響遥巴。
總結(jié):
1.函數(shù)內(nèi)部可以訪問函數(shù)外部的變量,但是函數(shù)外部不可以訪問函數(shù)內(nèi)部的變量享幽;
2.函數(shù)內(nèi)部如果有變量铲掐,則優(yōu)先使用內(nèi)部的變量,如果函數(shù)內(nèi)部沒有值桩,才會使用函數(shù)外部的變量摆霉;
3.當(dāng)子函數(shù)要使用某個變量時,子函數(shù)內(nèi)部沒有這個變量就會自動向父級函數(shù)查找奔坟,父級沒有繼續(xù)往上級函數(shù)查找携栋,知道查到全局作用域。