1. 程式人生 > >JavaScript的作用域詳解。

JavaScript的作用域詳解。

undefine 們的 標簽 不變 java 解決 rip 留言 img

很多人學過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的作用域詳解。