標籤:lob tracking obj 複習 lang 誤區 語法錯誤 首頁 原理
今天用了大量時間複習了範圍、先行編譯等等知識
看了非常多博文,翻了翻曾經看過的書(好像好多書都沒有講先行編譯)
發現當初認為自己學的非常明確,事實上還是存在一些思維誤區
(非常多博文具有誤導性)
今晚就整理了一下淩亂的思路
先整理一下先行編譯的知識吧,日後有時間再把範圍具體解說一下
大家要明確。這個先行編譯和傳統的編譯是不一樣的(能夠理解js先行編譯為特殊的編譯過程)
JavaScript是解釋型語言,
既然是解釋型語言,就是編譯一行。運行一行
傳統的編譯會經曆非常多步驟,分詞、解析、代碼產生什麼的
日後有時間再給大家科普
以下就給大家分享一下我所理解的JS先行編譯
JavaScript運行三部曲
指令碼運行js引擎都做了什麼呢?
- 文法分析
- 先行編譯
- 解釋運行
在運行代碼前。還有兩個步驟
文法分析非常easy。就是引擎檢查你的代碼有沒有什麼低級的語法錯誤
解釋運行顧名思義便是運行代碼了
先行編譯簡單理解就是在記憶體中開闢一些空間,存放一些變數與函數
理解了先行編譯對大家理解範圍相同有協助
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>
讓我們看看引擎對這段代碼做了什麼吧
- 頁面產生便建立了GO全域對象(Global Object)(也就是大家熟悉的window對象)
- 第一個指令檔載入
- 指令碼載入完成後。分析文法是否合法
- 開始先行編譯
- 尋找變數聲明,作為GO屬性。值賦予undefined
- 尋找函式宣告。作為GO屬性,值賦予函數體
//虛擬碼GO/window = { //頁面載入建立GO同一時候。建立了document、navigator、screen等等屬性。此處省略 a: undefined, c: undefined。 b: function(y){ var x = 1; console.log(‘so easy‘); }}
//虛擬碼GO/window = { //變數隨著運行流得到初始化 a: 1, c: function(){ //... }, b: function(y){ var x = 1; console.log(‘so easy‘); }}
- 運行函數b之前。發生先行編譯
- 建立AO使用中的物件(Active Object)
- 尋找形參和變數聲明,值賦予undefined
- 實參值賦給形參
- 尋找函式宣告,值賦予函數體
//虛擬碼AO = { //建立AO同一時候。建立了arguments等等屬性。此處省略 y: 100, x: undefined}
- 解釋運行函數中代碼
- 第一個指令檔運行完成。載入第二個指令檔
- 第二個指令檔載入完成後,進行文法分析
- 文法分析完成。開始先行編譯
大家要注意,
先行編譯階段發生變數聲明和函式宣告。沒有初始化行為(賦值),匿名函數不參與先行編譯
唯獨在解釋運行階段才會進行變數初始化
嗯~最後收一下尾
總結
先行編譯(函數運行前)※
1. 建立AO對象(Active Object)
2. 尋找函數形參及函數內變數聲明。形參名及變數名作為AO對象的屬性,值為undefined
3. 實參形參相統一,實參值賦給形參
4. 尋找函式宣告,函數名作為AO對象的屬性,值為函數引用
先行編譯(指令碼代碼塊script運行前)
1. 尋找全域變數聲明(包含隱式全域變數聲明。省略var聲明),變數名作全域對象的屬性,值為undefined
3. 尋找函式宣告。函數名作為全域對象的屬性,值為函數引用
理解了先行編譯對理解提升行為,this指向,範圍及效能等問題都有非常大協助
以後我也會總結這些問題
==首頁傳送門==
JavaScript先行編譯原理分析