JavaScript 預編譯原理
今天用了大量時間復習了作用域、預編譯等等知識
看了很多博文,翻開了以前看過的書(好像好多書都不會講預編譯)
發現當初覺得自己學的很明白,其實還是存在一些思維誤區 (很多博文具有誤導性)
今晚就整理了一下凌亂的思路
先整理一下預編譯的知識吧,日后有時間再把作用域詳細講解一下
大家要明白,這個預編譯和傳統的編譯是不一樣的(可以理解js預編譯為特殊的編譯過程)
JavaScript是解釋型語言,
既然是解釋型語言,就是編譯一行,執行一行
傳統的編譯會經歷很多步驟,分詞、解析、代碼生成什么的
日后有時間再給大家科普
下面就給大家分享一下我所理解的JS預編譯
JavaScript運行三部曲
腳本執行js引擎都做了什么呢?
在執行代碼前,還有兩個步驟
語法分析很簡單,就是引擎檢查你的代碼有沒有什么低級的語法錯誤
解釋執行顧名思義便是執行代碼了
預編譯簡單理解就是在內存中開辟一些空間,存放一些變量與函數
理解了預編譯對大家理解作用域同樣有幫助
JS預編譯什么時候發生
我當初思維誤區也發生在這里
預編譯到底什么時候發生
希望大家不要讓上面的運行過程讓你產生誤會,
誤以為預編譯僅僅發生在script內代碼塊執行前
這倒并沒有錯
預編譯確確實實在script代碼內執行前發生了
但是它大部分會發生在函數執行前
JS預編譯實例
舉例前,先來思考一下這幾個概念:
<script> var a = 1;// 變量聲明 function b(y){//函數聲明 var x = 1; console.log('so easy'); }; var c = function(){//是變量聲明而不是函數聲明?。? //... } b(100);</script><script> var d = 0;</script>讓我們看看引擎對這段代碼做了什么吧
1.頁面產生便創建了GO全局對象(Global Object)(也就是大家熟悉的window對象)
2.第一個腳本文件加載
3.腳本加載完畢后,分析語法是否合法
4.開始預編譯
查找變量聲明,作為GO屬性,值賦予undefined
查找函數聲明,作為GO屬性,值賦予函數體
//偽代碼GO/window = { //頁面加載創建GO同時,創建了document、navigator、screen等等屬性,此處省略 a: undefined, c: undefined, b: function(y){ var x = 1; console.log('so easy'); }}解釋執行代碼(直到執行函數b)
//偽代碼GO/window = { //變量隨著執行流得到初始化 a: 1, c: function(){ //... }, b: function(y){ var x = 1; console.log('so easy'); }}執行函數b之前,發生預編譯
//偽代碼AO = { //創建AO同時,創建了arguments等等屬性,此處省略 y: 100, x: undefined}解釋執行函數中代碼
第一個腳本文件執行完畢,加載第二個腳本文件
第二個腳本文件加載完畢后,進行語法分析
語法分析完畢,開始預編譯
重復最開始的預編譯步驟……
大家要注意,
預編譯階段發生變量聲明和函數聲明,沒有初始化行為(賦值),匿名函數不參與預編譯
只有在解釋執行階段才會進行變量初始化
嗯~最后收一下尾
總結
預編譯(函數執行前)※
1. 創建AO對象(Active Object)
2. 查找函數形參及函數內變量聲明,形參名及變量名作為AO對象的屬性,值為undefined
3. 實參形參相統一,實參值賦給形參
4. 查找函數聲明,函數名作為AO對象的屬性,值為函數引用
預編譯(腳本代碼塊script執行前)
1. 查找全局變量聲明(包括隱式全局變量聲明,省略var聲明),變量名作全局對象的屬性,值為undefined
3. 查找函數聲明,函數名作為全局對象的屬性,值為函數引用
理解了預編譯對理解提升行為,this指向,作用域及性能等問題都有很大幫助
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
新聞熱點
疑難解答