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(){
  funct![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200125232732660.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1d1TGV4,size_16,color_FFFFFF,t_70)ion 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。還是指向同一個堆內存空間,所以兩個值和類型都想相等(即同一個引用),即相等。

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

兩種類型都一樣:都是按值傳遞參數,並不是按引用傳遞參數。直接值代替參數。
在這裏插入圖片描述

發佈了323 篇原創文章 · 獲贊 549 · 訪問量 363萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章