hey,guys!我們一起總結一下JS預解析吧!
首先,我們得搞清楚JS預解析和JS逐行執行的關系。其實它們兩並不沖突,一個例子輕松理解它們的關系:
你去酒店吃飯,吃飯前你得看下菜譜,點下菜(JS預解析),但吃的時候還是一口一口的吃(JS逐行執行)!
OK,解決下面五個問題,JS預解析就算過了~~(前提:對JS變量作用域有清晰理解)
一、JS預解析是什么?
其實就是對程序要用到的材料(變量,函數)給一個初始值,並存到一個表中(我自己虛構的),當程序運行到那一行時,就來這個表看有沒有初始值,沒有就報錯~~
二、JS在什么情況下會進行預解析呢?
1.遇到<script></script>標簽對時;
2.遇到函數時;(因為變量是有作用域的)
三、JS對什么進行預解析?
1.函數傳參的變量
2.var 后面的變量
3.函數
四、那JS會給這些 變量、函數 賦予什么初始值呢?
1.凡是傳參,直接賦值參數;
2.凡是var 的,都會賦予一個 undefined 作為初始值;
3.凡是函數,直接賦予 函數本身 作為初始值;(所以這就是為什么我們可以把 函數調用 放到 函數聲明 之前的原因)
五、什么情況會改變 預解析 賦予的初始值呢?
有賦值功能的符號:=, +=, -=, *=, /=, ++, --等 (如果還有再添加..)
下面是來點實例:
1 alert(a); //報錯,沒有var 是不會進行預解析的 2 a = 0;
1 alert(a); //undefined 2 var a = 0; 3 alert(a); //0, =號 可以改變初始值
1 alert(a); //function a(){ alert('我是函數') }, undefined代表空,函數不是空的,當然要不是空的啦! 2 var a = '我是變量'; 3 function a(){ alert('我是函數') } 4 alert(a); //'我是變量', = 可以改變初始值
1 alert(a); //function a(){ alert('我是函數') }, undefined代表空,函數不是空的,當然要不是空的啦! 2 a++; 3 alert(a); //NaN, ++可以改變初始值 4 var a = '我是變量'; 5 function a(){ alert('我是函數') } 6 alert(a) //'我是變量', = 可以改變初始值
1 alert(a); //undefined 2 var a = 0; 3 alert(a); //0 4 function fn(){ 5 alert(a); //undefined;遇到函數,重新進行預解析 6 var a = 2; 7 alert(a); //2 8 } 9 fn() 10 alert(a); //0,fn里面的a與全局的a不是同一作用域的
1 alert(a); //undefined 2 var a = 0; 3 alert(a); //0 4 function fn(){ 5 alert(a); //0;因為沒var, 所以這里的a會被看作是全局的,往上查找,找到a=0,所以是0,如果全局也沒有就會報錯 6 a = 2; 7 alert(a); //2 8 } 9 fn() 10 alert(a); //2,fn把這全局的a修改了
1 function fn(a){ 2 alert(a); //undefined,JS會把傳參當作var一樣對待,相當於在fn內部定義了一個變量--> var a; 3 a = 2; 4 alert(a); //2,這里修改的不是全局的哦,改的是fn的局部變量哦 5 } 6 fn() 7 alert(a); //報錯
1 <script> 2 alert(a); //報錯,因為遇到<script>標簽對時,會先對這一塊進行預解析,運行到下面的才會再進行預解析,下面沒預解析,所以找不到a,於是報錯了 3 </script> 4 5 <script> 6 alert(a); //undefined 7 var a = 0; 8 alert(a); //0 9 </script>
1 <script> 2 var a; 3 </script> 4 5 <script> 6 alert(a); //undefined,雖然這個<script>標簽對沒有定義a,但會往上查找,上面的個<script>標簽定義了,所以為undefined 7 </script>
下面我們再看下這兩種情況的區別:
1 alert(a); //function a(){ alert('我是函數') } 2 function a(){ alert('我是函數') }
1 alert(a); //undefined,可以看出,凡是var,初始值都是undefined 2 var a = function (){ '我是函數' }
看,JS預解析也就這樣,沒我們想象中的那么難吧!
歡迎拍磚,覺得好的請點下推薦~~
之前還有一個地方不夠嚴謹,補充一下(2014.06.08):
對於函數內的預解析,可以理解成在執行前一瞬間,傳了參數后,進行預解析,然后才執行。
對於參數的預解析,傳參前,直接賦值undefined,傳參后,就是傳參的值;
所以在函數內的預解析 參數 是最先被解析到的。
function a(b){ //首先,執行的瞬間,傳參后進行預解析-> b = 1,然后往下找 b = b函數,最后b = b函數 alert(b); function b(){ alert(b); } b(); } a(1); //b函數, b函數
function a(b){ //傳參后進行預解析 -> b = c函數,然后往下找 b = b函數,最后b = b函數 alert(b); function b(){ alert(b); } b(); } a(c); //b函數, b函數 function c(){ return 123; }