JavaScript的作用域詳解。
很多人學過JS吧,可能有大神一笑而過,本篇文章自我撰寫,只適合新手不懂的同學們,大神請在2路公交車站左拐,也歡迎指點。
我在幾個月前是個連html是什麽都不知道的高中生菜鳥,但是學了幾個月之後,常常因為自己定義的一些函數沒有作用而十分苦惱。
我自己也去學過官方的作用域,但是感覺太膚淺,對於基礎差的同學們(入此行皆學生)是個非常容易混淆的一種概念。
廢話不多說,首先講原理,大家都知道JS是逐行執行,首先進入作用域只有有兩種方式:
1.當看到script標簽的時候,進入到作用域,也就是內置的<script></script>
2.當調用一個方法的時候,進入到作用域。比如上面代碼的fn();
這兩點切記!切記!
那麽,什麽是作用域?用通俗的話來說,就是開辟一個特定空間,將解析到的東西放在裏面。
解析前,還有一個道理,叫做JS預解析?為什麽叫“預”?就是沒執行之前先掃描一遍,將所有的var 和function存到作用域的倉庫裏。掃描出來所有var的值都預先是undefined!
我們首先進行預解析!
不多說,首先上第一題
1 var a=100; 2 3 function fn(){ 4 aert(a); 5 6 var a=200; 7 8 alert(a); 9 } 10 11 fn(); 12 alert(a); 13 var a; 14 alert(a); 15 var a=300; 16 alert(a);
這是第一題,大家可能有些人嘗試著去看題目解析了,但是你知道解析的原理和順序嗎?光靠經驗猜是沒用的。計算機按照死命令執行,不會因為你用久了就知道你的心思去幫你完成:
通過預解析掃描全部var 和function,第1行,解析器看到了個var a ,就在倉庫裏定義 var a=undefined;
在第3行,解析到一個function fn(){...} ,也丟到倉庫裏;繼續,
在第11行,解析器跳過,前面提過了,解析器只會對var 和 function進行預解析,
到13行,又看到了個var a,這時重新定義,但是var a依舊是undefined,值不變,有些同學可能不懂,略作解釋,前面提過了,所有在預解析裏解析所有的var 都是未定義;同名直接覆蓋,
後面沒有var和function了,所以預解析結束,進行逐行執行
第1行,var a=100;這裏我又要講一個方法了,就是當js執行的時候,會找有沒有+、-、*、/、++、--....如果有,就到預解析裏去尋找對應的值進行修改變量var;這裏a=100,有個“=”號,所以就去預解析倉庫裏修改var a=100;
第3行,函數,跳過。
第11行,調用了上面的函數,有些同學是不是想告訴我答案?100? NO NO NO,請看進入作用域的條件方式第二條!!!進入了函數!!重新定義另一個作用域,進入預解析,整個函數裏是不是只有一個變量var ? 然後就屁顛屁顛的跑到倉庫裏去定義 var a=undefined;(因為有var,所有重新定義這個函數內的變量a,不會和外面的產生沖突)解析完畢,進行執行,這下你知道alert(a);為什麽會執行undefined了吧? 繼續,接下來看到了var a=200;然後去作用域的倉庫裏修改var a=200;的值,接下來的alert(a)毫無疑問,彈出來200; 這個函數作用域主要的難點在於概念,你可能看到解析方法簡單,但是真執行的時候,你總是會忘記進入新的作用域是會重新定義這個新“倉庫”的;
第12行,根據第1行已經修改的變量得出 alert是100;
第13行,var a;首先,他這也是定義,但是沒有修改變量,所以變量a依舊是100;
第14行,毫無疑問,彈出100;
第15行,修改變量 變量a=300;
第16行,彈出300;
以上附出圖,希望同學們理解。
學計算機語言,最忌諱不學原理,可能前期你不會發覺,到後期,缺點就會慢慢展現出來;
還有第二題。。。
1 alert(a); 2 var a=1; 3 alert(a); 4 function a(){alert(a)}; 5 alert(a); 6 var a=3; 7 alert(a); 8 function a(){alert(4)}; 9 alert(a);
學過上文的同學們試著解下這道題,不要直接看答案,吸收過的東西才是自己的;
好,咱們來解決這道題;
首先預解析,進入作用域
第2行,添加var a=undefined;
第4行,添加function a(){alert(a)};
第6行,添加var a=undefined,但是已存在,覆蓋不變;
第8行,添加function a(){alert(4)};這是重點,同名函數,覆蓋第4行的數據,
所以現在這個作用域倉庫裏只有一條數據 :function a(){alert(4)};大家或許會很納悶,還有var a=undefined呢?
這裏向大家解釋下,當函數名稱和變量方法一樣的時候,變量就會被隱藏!對!是隱藏,不是覆蓋,不是刪除!
開始逐行執行,
大家先猜猜第一行執行什麽?
有人說是undefined,也有人想的是彈出4;。。。
結果是alert( function a() {alert(4)});對,你沒看錯,它彈出的是一整個函數。沒執行的函數,我當初也是這麽懵的;
接下來第2行,重新修改 ,隱藏函數function;var a=1
第3行,彈出1;
第4行,你們第一個念頭是不是重新覆蓋?NONONO,只有在預解析的情況下,函數名稱和變量名一樣的情況下才會讓變量隱藏,執行的時候,他們相互間是沒有關系的
第5行,所以,彈出1;
第6行,修改值var a=3;
第7行,彈出3;
第8行,又來混淆我們的耳目了,前面提過,執行的過程中,函數是不會替換相同變量名的;只作為一個方法被調用;
第9行,彈出3;
是不是被繞的有點暈了,還有呢!來個比較簡單的!
1 var a=1; 2 function fn1(){ 3 alert(a); 4 var a=2; 5 } 6 fn1(); 7 alert(a);
這道題自己做試試看吧。
然後我們開始,首先預解析
第1行 var a=undefined;
第2行 存儲function fn1(){..}
解析完畢。
第1行,修改變量a=1;
第6行,進入作用域,開始預解析;
找到var 得到 var a=undefined;
開始處理,彈出undefined;
第7行,由於作用域只限制於嵌套,不含被嵌套,所以彈出1;
但是。。我稍微修改下。你會麽?
1 var a=1; 2 function fn1(){ 3 alert(a); 4 a=2; 5 } 6 fn1(); 7 alert(a);
學會自己思考,才能消化,成為自己的知識,
首先 老規矩,預解析;
第1行 ,得到var a=undefined;(再次聲明:預解析裏的var都是undefined,直到逐行執行js代碼var a=?將其修改變量)
開始執行
第1行,得出var a=1;
第6行,進入作用域,由於fn1裏沒有var ,但是,需要這個a的值所以,會請求向上查找!這裏提起一個概念,函數內的請求只會去上級查找,也就是嵌套,比如一個員工,他想申請漲工資,只能先到小組組長申請,再到組長那,再到主管,再往上就是經理,CEO,一級沒有就繼續往上傳。到CEO都沒解決,那就只能(not a defined)沒戲了;
所以fn1()會彈出上級的變量a的值,也就是alert(1); 接下來,是一個全局變量,什麽是全局變量,意思是重新定義所有的變量a的值就是a=2;當然,後續執行程序的時候還是能通過var a=?進行修改的;
第7行,彈出2;
覺得自己懂了?再來一發;
1 var a=1; 2 function fn1(a){ 3 alert(a); 4 a=2; 5 } 6 fn1(); 7 alert(a);
嘿嘿,知道該怎麽做了嗎? 我僅僅添加了個參數a;
最好自己思考下,畢竟學習的知識不是一下子就能消化的;
動手!
首先預解析;
第1行,得到var a=undefined;
第2行,存儲一個函數;function fn1(a){...};
開始逐行執行;
第行,修改變量a的值;
第6行,調用,進入作用域,這裏重頭戲來了,這裏要再提一個概念,參數的傳參形式和var的賦值形式是一樣的;意思就是,你參數填的什麽(比如現在的fn1(a)),就直接相當於默認的var a(var a=undefined);只是還沒傳入值;接著解析,在下面也沒能找到var,所以直接彈出undefined;接下來的a=2只是一個傳遞參數(誰讓和參數重名呢?),不會進行全局變量;fn1()執行完;
第7行,第一行的var a=1沒有改變值,所以彈出1;
好了,希望我講的大家能接受,如有不好的地方,歡迎留言指正!本人虛心接受!
JavaScript的作用域詳解。