javascript
javascript基础拾遗——词法作用域
本來是想寫js面向?qū)ο蠊P記(二)關(guān)于封裝的,但是在敲實例代碼的時候,發(fā)現(xiàn)對作用域這個東西的概念有點模糊,翻閱了犀牛后,有點感覺了,就想著先記錄下此時的感受。
之所以取名叫做詞法作用域,是這個概念是js中相當(dāng)基礎(chǔ)也是極為重要的,很多想當(dāng)然的錯誤或感覺怪異的問題都是和這個東西有關(guān)。所以,本文主要說下這個名詞的概念以及討論下他牽扯出來的有關(guān)變量、函數(shù)、閉包的問題。
1.由變量開始談
習(xí)慣性先來段代碼:
1 var x = "globol value";
2 var getValue = function(){
3 alert(x); //彈出"undefined"
4 var x = "local value";
5 alert(x); //彈出"local value";
6 }
7 getValue();
代碼很簡單,首先定義了一個全局變量x并賦了初值,然后寫了個getValue的方法,之后我們用alert彈出x的值,但是結(jié)果是undefined,不是global value也不是local value,這個我們可能會感覺到奇怪。其實理解這個問題的關(guān)鍵就是要清楚x的作用域。
第一個var x中的x是全局變量,說到這里順帶說下,js解釋器在執(zhí)行任何代碼之前會先創(chuàng)建一個全局對象(global object),全局變量就是相當(dāng)于這個全局對象的一個屬性。同理,對于getValue這個函數(shù),就會生成一個叫做調(diào)用對象的東西,局部變量就是這個調(diào)用對象的屬性,例子中第二個var x中的x就是局部變量。
2.主角登場
說了以上的東西其實是為了將本文的主角——詞法作用域。這個是何方神圣呢?要理解的話,其實我們可以對比傳統(tǒng)面向?qū)ο蟮?#xff08;如JAVA、C#)中的變量的作用域,我們知道C#中的變量作用域是塊級的,即這個變量只能活動在定義他的一個直接外界內(nèi),如if子句內(nèi),for子句內(nèi)定義的變量外界是無法讀取的。而js中呢,變量卻不是這樣的,在同一個函數(shù)內(nèi)定義的變量其它的成員是可以訪問的??磦€例子會清楚很多:
1 function test(o){
2 var i = 0;
3 if(typeof o == "object"){
4 var j = 0;
5 for(var k=0; k < 10; k++){
6 document.write(k);
7 }
8 document.write(k); //k是可以被訪問到的,即使他在for子句內(nèi)
9 }
10 document.write(j); //說明j是可以被訪問到的,即使他在if子句內(nèi)
11 }
清楚了這一點后,就來理解下js中關(guān)于詞法作用域的含義。當(dāng)定義了一個函數(shù)后,當(dāng)前的作用域就會被保存下來,并且成為函數(shù)內(nèi)部狀態(tài)的一部分,這個是很重要的一個概念。下面我們回到開篇的那個例子,當(dāng)getValue函數(shù)被定義的時候,他的作用域被保存起來,還有被加到作用域鏈上,他的上端就是全局執(zhí)行環(huán)境。當(dāng)調(diào)用getValue方法的時候,js解釋器首先會把作用域設(shè)置為定義函數(shù)的時候的那個作用域(即之前保存那個),接下來,他在作用域的前加上調(diào)用對象即getValue這個函數(shù),再在他的上端加上全局對象。暈了沒?還是看下我畫的圖把:
這樣比較清楚了把,這個作用域鏈其實和原型鏈有點相似,也好似在很作用域內(nèi)找不到就會向上去找。比方說開篇那個例子,找x的時候,(對了這里要先介紹下js的預(yù)定義機制,就是js解釋器會先對var定義的變量進行初始化,應(yīng)該說只是起了定義的作用當(dāng)沒賦值),會先在本作用域內(nèi)找,有預(yù)定義知可以找到x,但是沒賦值,所以是undefined值。知道了這點我們來知道開篇那個代碼其實是等價于下面這個的:
1 var x = "globol value";
2 var getValue = function(){
3 var x;
4 alert(x); //彈出"undefined"
5 x = "local value";
6 alert(x); //彈出"local value";
7 }
8 getValue();
實際上js解釋器做的事情應(yīng)該是按以上這個例子執(zhí)行的,所以從另一個角度說,將變量的定義放在開頭這個約定是有意義并且有益處的。
3.延伸
清楚了以上關(guān)于詞法作用域的概念后,我們就不難理解閉包的概念了,他只是用到了作用域鏈的不可向下性(我取的名詞..),即下面的作用域可以訪問上面的,但上面的不可以訪問下面的。當(dāng)然這只是構(gòu)成閉包的一個條件,閉包更重要的還是外部函數(shù)持有內(nèi)部函數(shù)的一個嵌套函數(shù)的引用,由于閉包不是本文主要要討論的(ps:談封裝的時候會說到),所以只是簡單看下例子:
1 function foo(){
2 var age = 10;
3 function boo(){
4 age += 10;
5 return age;
6 }
7 return boo;
8 }
9
10 var tx = new foo();
11 alert(tx()); //20
4.總結(jié)
詞法作用域的討論就先這樣了,我想說得是這個概念還是相當(dāng)重要的。當(dāng)然本文的內(nèi)容也只是我針對書本介紹的自我的一些看法和理解,有不得當(dāng)?shù)牡胤较M魑恢赋?#xff0c;好了,回去睡覺了~
轉(zhuǎn)載于:https://www.cnblogs.com/Quains/archive/2011/04/12/2013121.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的javascript基础拾遗——词法作用域的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 类WebOS(添加了主界面,及相关功能代
- 下一篇: MD5数据加密于文件加密