首頁 >web前端 >js教程 >JavaScript預解釋是什麼? JavaScript預解釋的解析(附程式碼)

JavaScript預解釋是什麼? JavaScript預解釋的解析(附程式碼)

不言
不言轉載
2018-11-16 14:58:231791瀏覽

本篇文章帶給大家的內容是關於JavaScript預解釋是什麼? JavaScript預先解釋的解析(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

JavaScript是一門解釋型的語言, 想要運行JavaScript程式碼需要兩個階段

  • #編譯階段: 編譯階段就是我們常說的JavaScript預解釋(預處理)階段,在這個階段JavaScript解釋器將完成把JavaScript腳本代碼轉換到字節碼

  • #執行階段: 在編譯階段JavaScript解釋器借助執行環境把字節碼產生機械碼,並從上到下依序執行

本文就著重預解釋,框架圖如下:

JavaScript預解釋是什麼? JavaScript預解釋的解析(附程式碼)

一、什麼是預解釋

預解釋:JavaScript程式碼執行之前,瀏覽器首先會預設的把所有帶var和function的進行提前的宣告或定義

1.理解宣告與定義

宣告(declare):如var num;=>告訴瀏覽器在全域作用域中有一個num的變數了;如果一個變數只是宣告了但是沒有賦值,預設​​的值是undefined

定義(defined):如num=12;=>給我們的變數賦值。

2.對於帶var和function關鍵字的在預解釋的時候操作不一樣的

var =>在預解釋的時候只是提前的聲明

function =>在預先解釋的時候提前的宣告定義都完成了

3.預解釋只發生在目前的作用域下。

例如:開始只對window下的進行預解釋,只有函數執行的時候才會對函數中的進行預解釋

二、作用域鏈

#1 .如何區分私有變數和全域變數?

1)在全域作用域下宣告(預先解釋的時候)的變數是全域變數

2)只有函數執行會產生私有的作用域,例如for(){}、if(){}和switch(){}都不會產生私有作用域

3)在"私有作用域中宣告的變數(var 宣告)"和"函數的形參"都是私有的變數。在私有作用域中,程式碼執行的時保遇到了一個變量,首先我們需要確定它是否為私有的變量,如果是私有的變量,那麼和外面的沒有在何的關係;如果不是私有的,則往目前作用域的上級作用域進行查找,如果上級作用域也沒有則繼續查找,一直找到window為止,這就是作用域鏈。

我們舉個例子來區別私有變數和全域變數:

//=>变量提升:var a;var b;var c;test=AAAFFF111;
var a=10,b=11,c=12;
function test(a){
//=>私有作用域:a=10 var b;
a=1;//=>私有变量a=1
var b=2;//=>私有变量b=2
c=3;//=>全局变量c=3
}
test(10);
console.log(a);//10
console.log(b);//11
console.log(c);//3

判斷是否是私有變數一個標準就是是否是在函數中var宣告的變數和函數的形參都是私有的變數。本題目在test函數中a是形參和var b定義的變數b都是私有變數。

2.函數傳參

這是因為當函數執行的時候,首先會形成一個新的私有的作用域,然後按照如下的步驟執行:

#1)如果有形參,先給形參賦值

2)進行私有作用域中的預解釋

3)私有作用域中的程式碼從上到下執行

我們來看一道例題

var total=0;
function fn(num1,num2){
console.log(total);//->undefined 外面修改不了私有的
var total=num1 +num2;
console.log(total);//->300
}
fn(100,200);
console.log(total);//->0 私有的也修改不了外面的

3.JS中記憶體的分類

堆疊記憶體:用來提供一個供JS程式碼執行的環境,即作用域(全域作用域/私有的作用域)
堆記憶體:用來儲存引用資料型別的值。物件儲存的是屬性名稱和屬性值,函數儲存的是程式碼字串。

三、全域作用域下帶var和不帶var的差別

我們先來看以下兩個例子:

//例题1
console.log(num);//->undefined
var num=12;
//例题2
console.log(num2);//->Uncaught ReferenceError:num2 is not defined 
num2=12;//不能预解释

當你看到var num=12時,可能會認為只是個聲明。但JavaScript實際上會將其看成兩個宣告語句:var num;和 num=12;第一個定義宣告是在預先解釋階段進行的。第二個賦值聲明會被留在原地等待執行階段。 num2=12 相當於為window增加了一個叫做num2的屬性名,屬性值是12;而var num=12 首先它相當於為全域作用域增加了一個全域變數num,它也相當於為window增加了一個屬性名num2,屬性值是12。 兩者最大差別:帶var的可以進行預解釋,所以在賦值的前面執行不會報錯;不帶var的是不能進行預解釋的,在前面執行會報錯;

接下來我們舉例說明:

//例题1
var total=0;
function fn(){
console.log(total);//undefined
var total=100;
}
fn();
console.log(total);//0
//例题2
var total=0;
function fn(){
console.log(total);//0
total=100;
}
fn();
console.log(total);//100

範例1中帶var變數在私有作用域中可以預先解釋,所以第一個console打出來的值為undefined。 私有作用域中出現的一個變數不是私有的,則往上級作用域進行查找,上級沒有則繼續向上查找,一直找到window為止,例題2中不帶var變數不是私有的,所以往上級找

四、預解釋五大毫無節操的表現

1.預解釋的時候不管你的條件是否成立,都要把帶var的進行提前的聲明。

請看下面這道範例:

if(!("num" in  window)){
var num=12;//这句话会被提到大括号之外的全局作用域:var num;->window.num; 
}
console.log(num);//undefined

2.预解释的时候只预解释”=”左边的,右边的值,不参与预解释

请看下面这道例题:

fn();//报错
var fn=function (){  //window下的预解释:var fn;
console.log("ok");
};

3.自执行函数:定义和执行一起完成了。

自执行函数定义的那个function在全局作用域下不进行预解释,当代码执行到这个位置的时候定义和执行一起完成了。常见有以下几种形式:

(function(num){})(10);
~function(num){}(10);
+function(num){}(10);
-function(num){}(10);
!function(num){}(10);

4.函数体中return下面的代码虽然不再执行了,但是需要进行预解释;return后面跟着的都是我们返回的值,所以不进行预解释;

function fn(){
//预解释:var num;
console.log(num);//->undefined
return function(){};
var num=100;
}

5.函数声明和变量声明都会被提升。但是一个值得注意的细节(这个细节可以出现在有多个“重复”声明的代码中)是函数会首先被提升,然后才是变量。在预解释的时候,如果名字已经声明过了,不需要从新的声明,但是需要重新的赋值;

我们先来看下两个简单的例子:

//例题1
 function a() {}
  var a
  console.log(typeof a)//'function'
//例题2
  var c = 1
  function c(c) {
    console.log(c)
    var c = 3
  }
  c(2)//Uncaught TypeError: c is not a function

当遇到存在函数声明和变量声明都会被提升的情况,函数声明优先级比较高,最后变量声明会被函数声明所覆盖,但是可以重新赋值,所以上个例子可以等价为

 function c(c) {
  console.log(c)
    var c = 3
  }
 c = 1
 c(2)

接下来我们看下两道比较复杂的题目:

//例题3
fn();
function fn(){console.log(1);};
fn();
var fn=10;
fn();
function fn(){console.log(2);};
fn();

1.一开始预解释,函数声明和赋值一起来,fn 就是function fn(){console.log(1);};遇到var fn=10;不会重新再声明,但是遇到function fn(){console.log(2);}就会从重新赋值,所以一开始fn()的值就是2

2.再执行fn();值不变还是2

3.fn重新赋值为10,所以运行fn()时报错,接下去的语句就没再执行。

//例题4
alert(a);
a();
var a=3;
function a(){
alert(10)
}
alert(a);
a=6;
a()

1.函数声明优先于变量声明,预解释时候,函数声明和赋值一起来,a就是function a(){alert(10)} ,后面遇到var a=3,也无需再重复声明,所以先弹出function a(){alert(10)}

2.a(),执行函数,然后弹出10

3.接着执行了var a=3; 所以alert(a)就是显示3

4.由于a不是一个函数了,所以往下在执行到a()的时候, 报错。


以上是JavaScript預解釋是什麼? JavaScript預解釋的解析(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除