JS預解析機制


JS的預解析過程:

1,預解析

2,再逐行解讀代碼,

實例:
----------------------------
<script>
var name="xm";
var age=18;
function fn(argument){
console.log(name);//輸出未定義:undefined
var name="xh";
var age=12;
}
</script>
----------------------------
解析:

全局作用域,局部作用域,都是通過以下兩個步驟進行預解析的。

1,先讀取有var 的變量(沒有使用var的變量是不會被預解析的),給賦值為:undefined。如果兩個變量重名,並不影響預解析的過程,就寫一個變量就行,因為都將變量賦值為undefined(在逐行讀取時,只是不同的賦值而已。),如果有函數名和變量重名,那就直接去掉變量,不進行解析。如果函數中存在參數,那么參數也一樣使用var進行解析。如:var argument=undefined;

2,再讀取function后面的函數---fn,如果有多個函數名重復,那么取最后面一個函數進行聲明。

上面實例有兩個作用域,一個是window變量對象的全局作用域,一個是fn變量對象的局部作用域。

預解析過程如下:

1,window:

  var name=undefined;

  var age=undefined;

  function fn(argument){
console.log(name);
var name="xh";
var age=12;
}

2,fn:

  var name=undefined;

  var age=undefined;

  var argument=undefined;

預解析就完成了。然后就是逐行解讀代碼。

通過逐行解讀代碼進行賦值,改變變量屬性值。如果遇到函數,那么就直接跳過,因為預解析時已經聲明過。

所以,上面實例:console.log(name); 輸出為: undefined。

實例1:

<script>
console.log(fn);
function fn(){}; //預解析:function fn(){};
</script>

輸出結果:function fn(){};

實例2:
<script>
console.log(fn);
  var fn=function(){}; //預解析:var fn=undefined;
</script>

輸出結果:undefined 未定義。

實例3:
<script>
console.log(a);//所以這里a是沒有定義,運行就報錯。運行未定義變量報錯,運行未定義屬性返回undefined
   a=1;//預解析沒有變量。
</script>
輸出結果:這里的a沒有定義,所以報錯,未定義。
-----------------------
<script>
console.log(a); //預解析中只剩下一個函數a,所以這里輸出是整個函數a。 函數里面的表達式不進行預解析
var a=1; //聲明一個變量 a 進行賦值,所以跟預解析沒關系
console.log(a);//所以這里輸出為:1。
function a(){ //兩個函數重名只保留最后一個,所以這個函數不進行解析,在逐行解讀代碼時,沒有進行解析的代碼也是跳過的。
console.log(2);
};
console.log(a);//函數被當成變量賦值為:1,a就是一個變量。所以這里輸出為:1。
var a=3; //聲明一個變量 a 進行賦值,所以跟預解析沒關系
console.log(a);//這里輸出為:3。
function a(){ //被預解析的函數就直接跳過不進行解析,因為預解析時,已經聲明過了。
console.log(4);
};
console.log(a);//函數被當成變量賦值為:3。所以這里輸出為:3。
a(); //函數被當成變量賦值為:3。所以這里的a為變量,變量不可以當做函數執行。
</script>

輸出結果:
function a(){console.log(4);}

1

1

3

3

報錯(a=3,不能當函數執行);

預解析:
//var a=undefined; 變量a與函數 a 重名,所以變量不進行預解析。
//兩個函數重名,只對最后一個進行預解析。
function a(){
  console.log(4);
}
-----------------------
預解析是一個標簽執行完畢並且逐行解讀代碼完成,才執行第二個標簽的預解析和逐行代碼解讀:
以下是存在兩個script的情況,進行預解析:
<script>
console.log(a);//這個標簽預解析后沒有變量需要聲明,再執行console.log(a); a是沒有聲明的變量,所以報錯。
</script>
<script>
var a=1;
</script>
輸出結果為:報錯。第一個標簽的a沒有聲明。
預解析是一個標簽執行完畢並且逐行解讀代碼完成,才執行第二個標簽的預解析和逐行代碼解讀:
以下是存在兩個script的情況,進行預解析:
<script>
var a=1;//預解析:var a=undefined; 再被復制為1。執行完畢,再進行下面一個標簽預解析,在逐行解讀代碼。
</script>
<script>
console.log(a); //所以這里輸出為:1。
</script>

輸出結果:1。
-----------------------
<script>
var a=1; //解析:var a=undefined;
function fn(a){ //解析:var a=undefined;
console.log(a); //執行完fn(a)后,輸出1。因為這里的a變成全局變量了。重點。
a=2;
}
fn(a); //這里的a是全局變量,因為局部變量不能再全局中使用,只有全局變量才能在局部中使用。所以這個a=1。
console.log(a); //局部變量不能再全局中使用,只有全局變量才能在局部中使用。所以這里輸出1。
</script>

輸出為:1 , 1

預解析:
window變量對象的屬性以及方法:
  var a=undefined;
  fn(a){console.log(a); a=2;};

fn變量對象的屬性以及方法:
var a=undefined //這里的 a 是參數。
------------------------
不要在代碼塊中聲明函數,因為這樣有些老的狐火瀏覽器無法進行正確的預解析。
if(){
  function fn_name(argument){.....body......}
}
for(){
  function fn_name(){.....body......}
}

 =================總結=====================

上圖:

基本變量復制(這里應該是賦值)時,創建一個副本:

var name="xm";

   name="xh";//基本類型賦值,跟上面一個值無關。即:兩個值,在棧內存中開辟了兩個位置存放數據。

引用類型賦值的其實是指針:

var xh={sex:"female" age:18};

var xm=xh;//把xh的引用賦值給xm。還是指向同一個堆內存空間,所以兩個值和類型都想相等(即同一個引用),即相等。

基本數據類型和引用數據類型傳遞參數。

兩種類型都一樣:都是按值傳遞參數,並不是按引用傳遞參數。直接值代替參數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM