剛接觸到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
有時候咱們會想,一段JS代碼是如何執行的呢?其實,在JS代碼被執行以前,一般都有一個編譯過程。
這個編譯過程其實很複雜,但整體來講,逃不過編譯過程的步驟,只不過JavaScript是在這個步驟之中對代碼作了優化處理。
詞法分析主要是將一段程序分解成有意義的代碼塊,便於對分解的代碼塊作解析。
好比,var age = 10;這一段代碼將會被分解成 var、age、=、十、;。這是5個詞法單元。
這些單元分析完畢以後,便會給解析器調用,生成相應的AST(抽象語法樹)。
解析詞法單元,是爲了生成AST,那麼到底什麼是AST呢,咱們來看一段代碼以及解析生成的AST。
一樣是var age = 10;這段代碼,被解析器解析成了一段樹形結構的結構,這個結構,就是抽象語法樹AST。你能夠經過這個網站來查看生產的AST:AST解析器
而抽象語法樹,又是能夠轉換成可執行代碼。這就涉及到編譯的第三個階段。
生成可執行代碼的過程,至關因而再把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中的聲明和賦值又是如何的一個流程呢?
好比,var age = 10;這段代碼,在JavaScript中的編譯方式是如何呢?
在JavaScript中,這段代碼大概至關因而以下兩個過程:
var age = undefined; // 隱式賦值,編譯階段 age = 10; //變量賦值 執行階段
函數聲明也是如此:
// 這一段代碼就是一個完整的函數聲明,在編譯階段中,會先執行全部聲明,纔會依次執行代碼操做。 function log() { console.log('this is log') }
這個時候,咱們再回頭來,想一下提高機制是什麼?
JavaScript的執行,被分爲了兩個階段,分別是編譯階段,以及執行階段。依照這個來看,所謂的提高機制(有的叫作變量提高,考慮到函數的定義,並未用這個名詞),就是JavaScript引擎把變量聲明和函數聲明在編譯階段首先進行默認賦值,以後,在程序執行階段,纔會被代碼真正的執行。也就是說,針對聲明先提高,後執行。
注意:函數聲明和變量都有提高機制,二者之間也有優先級。這都遵循一個原則:函數優先原則。也就是說,函數聲明會提高到普通變量聲明以前。
變量提高,是一個值得去探究的概念,只有理解了這個概念,咱們理解JavaScript的執行機制將會變得清晰明瞭起來。
文中有什麼描述不當的,但願各位大佬能指出,你們共同窗習,一塊兒進步。