漫談JavaScript中的提高機制(Hoisting)

前言

剛接觸到JavaScript的時候,便知道JavaScript是按順序執行的,是如瀏覽器的解析DOM樹同樣的流程,解析DOM結構的時候,若是遇到JS腳本或者外聯腳本便會中止解析,繼續下載腳本以後,執行腳本,而後再解析DOM。javascript

然而,卻所以經常碰到問題。java

看以下代碼以及輸出:瀏覽器

var name;
console.log(name);   // undefined
name = 'tom';

age  = 10;
var age;
console.log(age);  // 10

  

上面的代碼讓咱們產生了疑惑,咱們僅僅聲明瞭name的時候,打印出來值是undefined,按理說,從新聲明age以後,age的值應該也是undefined纔對,可是輸出來的倒是10。這到底是怎麼回事兒呢?babel

咱們的通用解釋是,遇到了變量提高。函數

而這樣的狀況,咱們在函數中也會看到,請看下面代碼:學習

log();
console.log(name);
var name = 'tom';
function log() {
    console.log('this is log');
}

  

上面代碼的輸出結果是什麼?優化

輸出結果:
this is log
undefined

  

爲何會產生這樣的情形呢?咱們通用的解釋是,函數聲明提高了。網站

而針對這兩種狀況,就是咱們常常遇到的提高機制,也就是咱們常說的Hoisting。this

而僅僅只是一句提高機制來解釋這種現象,仍是以爲雲裏霧裏,要是我以前可能也就不明覺厲的哦了一聲,而後就再也不理會這樣的東西了,那麼究竟爲何會出現這樣的狀況呢?.net

JavaScript是如何被編譯的呢

有時候咱們會想,一段JS代碼是如何執行的呢?其實,在JS代碼被執行以前,一般都有一個編譯過程。

這個編譯過程其實很複雜,但整體來講,逃不過編譯過程的步驟,只不過JavaScript是在這個步驟之中對代碼作了優化處理。

第1、詞法分析

詞法分析主要是將一段程序分解成有意義的代碼塊,便於對分解的代碼塊作解析。

好比,var age = 10;這一段代碼將會被分解成 var、age、=、十、;。這是5個詞法單元。

這些單元分析完畢以後,便會給解析器調用,生成相應的AST(抽象語法樹)。

第2、解析詞法單元

解析詞法單元,是爲了生成AST,那麼到底什麼是AST呢,咱們來看一段代碼以及解析生成的AST。

一樣是var age = 10;這段代碼,被解析器解析成了一段樹形結構的結構,這個結構,就是抽象語法樹AST。你能夠經過這個網站來查看生產的AST:AST解析器

而抽象語法樹,又是能夠轉換成可執行代碼。這就涉及到編譯的第三個階段。

第3、生成可執行代碼

生成可執行代碼的過程,至關因而再把AST轉換成瀏覽器可執行的代碼,或者是各類語言引擎可執行的代碼。

好比咱們常見的babel,可讓咱們用ES6的語法去開發程序,其實就是依靠babel編譯器,將咱們的ES6代碼編譯成ES6的AST,而後將ES6的AST轉換成ES5的AST或者ES3的AST,最後將AST轉成ES5或ES3的代碼來讓瀏覽器執行。

同理,TypeScript的TSC也是一個編譯器,作的事情和babel是同樣的,只不過二者編譯出來的ES6的AST有略微的差異,這樣就形成了TypeScript用不了Babel社區的豐富多樣的插件,如eslint等。

由於eslint語法檢查,正是基於AST作的。

那麼上面這個編譯過程有什麼用呢?

JavaScript中的聲明和賦值

理解了語言的編譯過程,那麼JavaScript中的聲明和賦值又是如何的一個流程呢?

好比,var age = 10;這段代碼,在JavaScript中的編譯方式是如何呢?

在JavaScript中,這段代碼大概至關因而以下兩個過程:

var age = undefined;     // 隱式賦值,編譯階段
age = 10;    //變量賦值   執行階段

  

函數聲明也是如此:

// 這一段代碼就是一個完整的函數聲明,在編譯階段中,會先執行全部聲明,纔會依次執行代碼操做。
function log() {
    console.log('this is log')
}

  

這個時候,咱們再回頭來,想一下提高機制是什麼?

再看提高

JavaScript的執行,被分爲了兩個階段,分別是編譯階段,以及執行階段。依照這個來看,所謂的提高機制(有的叫作變量提高,考慮到函數的定義,並未用這個名詞),就是JavaScript引擎把變量聲明和函數聲明在編譯階段首先進行默認賦值,以後,在程序執行階段,纔會被代碼真正的執行。也就是說,針對聲明先提高,後執行。

注意:函數聲明和變量都有提高機制,二者之間也有優先級。這都遵循一個原則:函數優先原則。也就是說,函數聲明會提高到普通變量聲明以前。

總結

變量提高,是一個值得去探究的概念,只有理解了這個概念,咱們理解JavaScript的執行機制將會變得清晰明瞭起來。

文中有什麼描述不當的,但願各位大佬能指出,你們共同窗習,一塊兒進步。

個人博客:http://www.gaoyunjiao.fun/?p=143

相關文章
相關標籤/搜索