轉載地址:
http://blog.csdn.net/itzhengmaolin/article/details/54565201
作用域:在一定的范圍內,對其進行讀、寫操作“js解析器”執行的過程至少2步:1、"找一些東西":比如 var 、function、參數2、逐行解讀代碼例:
alert(a);var a=1;function fn1(){ alert(2);}
解析過程:
1、JS的預解析過程 原則:遇到重名的:只留一個(變量和函數重名了,就只留下函數。無論變量在上還是函數在上,與上下是沒關系的,跟有值沒值有關系。因為變量=undefined,函數=整個函數塊,相比之下有具體值的級別更大)
找到var關鍵字,然后定義其變量名等于undefined,不會管后面的值(在"JS解析器"執行的過程中,所有的變量都等于未定義) 如:a=undefined
找到function關鍵字,然后用其函數名等于其整個函數塊。(所有的函數,在正式運行代碼之前,都提前賦了一個值,這個值為整個函數塊) 如:fn1=function fn1(){alert(2);}
2、逐行解讀代碼過程: 表達式可以修改"預解析"的值。函數的聲明不屬于表達式,改變不了什么東西這個過程遵循"從上往下,從左往右"的順序執行。當執行一句完畢后,到倉庫中查找是否有這個"東西"(變量、函數等)。如果有則彈出其一開始在倉庫的值(使用alert方法)遇到表達式(=+ - * / % ++ -- ! 參數……等即能改變值的東西)簡單來說,找var 、function、參數,并將變量賦值為undefined、函數名=整個函數,然后將他們存儲在倉庫中,在進行逐行解讀代碼的時候,在倉庫中提取或修改
練習:
解析過程
1、找關鍵字(var、function、參數)找到37行的"var a",執行過程:a=undefined找到39行的"function a(){alert(2);}",執行過程:a=function a(){alert(2);}因為倉庫里有重名的a,所以要比較優先級,值為函數的大于值為未定義,所以執行過程為a=function a(){alert(2);}找到41行的"var a ",執行過程:a=undefined因為倉庫里有重名的a,所以要比較優先級,值為函數的大于值為未定義,所以執行過程為a=function a(){alert(2);}找到43行的"function (){alert(4);}",執行過程:a=function (){alert(4);}因為倉庫里有重名的a,所以要比較優先級,值同為函數則比較先后,后面的覆蓋前面的,所以執行過程為a=function a(){alert(4);}2、逐行解析:從上往下,從左到右依次執行代碼。從36行開始,a的一開始值為function a(){alert(4);}執行37行時,修改倉庫中a的值,則變為1執行39行時,并不影響a的值,所以a的值還是1后面亦是如此
一個頁面兩個script標簽,瀏覽器遇到script標簽會用"js解析器"來解析,只有解析完第一個script標簽的內容后在執行下一個script標簽內的內容,所以下面alert(a); 會報錯 a is no defined。
這就是當引用別人寫的jQuery庫時,在對其修改
var a = 1;
function fn1()
{
alert(a); //undefined var a = 2;
}
fn1();
alert(a);
//1解析過程:
1、預解析:a=undefined;fn1=function fn1(){ alert(a); var a = 2;}
2、逐行解析;a=1遇到函數調用fn1() --函數也是一個局部的域,只要是一個域就會發生預解析和逐行解讀代碼。相當于其有一個小的倉庫。可以理解為1個大倉庫包含著1個小倉庫,大倉庫里的a和小倉庫里的a是不同的世界,互不影響。函數調用屬于表達式 函數里的預解析: a=undefined; //這里的a是局部的,外面的是全局的,兩者沒關系 函數里的逐行解析: 執行函數里的alert(a); 先找局部倉庫里的a,所以彈出undefined 在執行函數里的var a=2; 所以局部里的a=2,并沒有影響全局中的a=1 函數執行完畢后會有垃圾回收機制等
函數調用完畢后,繼續全局的逐行解析
var a = 1;function fn1(){alert(a); // 1a = 2;
//注意這里沒用var聲明}fn1();alert(a); // 2函數里的預解析過程為空,執行函數里的逐行解析代碼:當執行到alert(a);沒找到a,會順著函數的作用域跳到上一級(從子級作用域返回到父級作用域的過程叫作用域鏈,由里到外找)。執行到"a=2"時,發現小倉庫里沒有a,則由里到外找,找到其父級有a,則修改a的值為2
所以,加var與不加var的區別體現出來了。不加var,會修改全局變量的值
var a = 1;function fn1(a){alert(a); // undefineda = 2;}fn1();alert(a); // 1
參數本質就是一個局部變量。跟上面的其中一種情況(如下)很類似函數預解析時沒有發現var、function ,卻發現了參數,所以a=undefined。然后逐行解讀代碼,當讀到"alert(a);",執行結果為undefined當讀到"a=2;",它會就近找小倉庫里有沒有a,執行結果為a=2,全局的a還是1不影響