1. 程式人生 > >js預編譯的四部曲

js預編譯的四部曲

再次複習了一下作用域和預編譯的知識仔細的看了下老師視訊和部落格

學習到了一些關於預編譯和作用域的知識和大家分享一下!

眾所周知javascript是解釋性語言,主要特點為解釋一行執行一行。

而在js執行時會進行三件事:1語法分析  2.預編譯  3.解釋執行

    語法分析會在程式碼執行前對程式碼進行通篇檢查,以排除一些低階錯誤

    預編譯發生在程式碼執行的前一刻

    解釋執行顧名思義就是執行程式碼

我先給大家舉幾個預編譯的小例子:

                var a = 123;

console.log(a);  此時他返回的值會是123;

   但如果我們調換位置:

                console.log(a);

                    var a = 123;      我們得到的結果便會是undefined。(由於js解釋性語言的原因,先執行console.log,而由於預編譯的原因瀏覽器並不會報錯)

如果我們在次嘗試不定義變數直接獲取:

                console.log(a);  此時我們會發現瀏覽器會進行報錯。//Uncaught ReferenceError: a is not defined

                                                                                                               這條語句提示我們a沒有定義

到這裡有些人會有疑問為什麼在console.log前,後和不定義a會有如此大的差別,這就是預編譯起到的作用

在具體講解預編譯之前要先幫大家瞭解幾點小知識,如下:

預編譯的前奏

   1. imply global 暗示全域性變數:即任何變數,如果變數未經宣告就賦值,此變數就為全域性物件(window)所有。

              簡單解釋起來就是,如果在js中我們在賦值時經常先定義一個變數,如:var a = 123;

              此時123這個數字便被賦予了a這個變數,此時我們在控制檯console.log(a)就會得到a的值123;

              這時就會我們就會有個疑問,如果我們沒有定義變數直接進行賦值還會打印出值麼。

              答案是肯定的,此時如果我們未定義變數直接賦值,如:

                b = 456;

            此時a會被認為是全域性的一個物件,即window下的一個值,此時我們在控制檯下console.log(b)同樣可以得到b的值456。

            此時我們可以認為    b = 123   ————>   window.b  =456

   2. 一切宣告的全域性變數,全是window。

簡單說明就是我們 var  c = 789   ===>    window.c = 789(即:c =789)

預編譯(粗淺版本)

下面我們來看一下對預編譯最基本的膚淺理解(該理解非常粗淺無法解決複雜問題):

函式宣告整體提升

    變數,宣告提升

個人理解:在函式執行前函式宣告(function(){})會整體提升至邏輯的最前方,

                 變數則會把自身的宣告提升到程式的最最前方。

//註釋  var  a =123;是變數宣告+賦值

    var  a:變數宣告

    a  = 123 變數賦值

    在預編譯時我們不看賦值,只把變數的宣告提升,因此若在賦值前列印會提示undefined;

此時我們就可以理解之前的問題了:

        先列印再定義:

                    console.log(a);

                    var a = 123;  

在執行前var  a提升至程式碼的最最前端 ,提升後我們再列印 a,由於此時a未被賦值因此列印提示undefined。

                     console.log(a);

      不定義:

                    console.log(a);

  此時由於沒有a的定義,所以會報錯提示a is not defined;即:a未定義。

看似很好理解但是如果程式碼稍微複雜便無法解決,例如(這是一道老師給出的題我想破了頭):

            console.log(a);   fun

            function a(a) {

                        var  a  =  456;

                        var  a   =function  ()  {

                }

                       a();

            }

                    var  a  =   123;

下面我們來看一下真正的預編譯:

預編譯(精裝版本):

    預編譯的四部曲:

        1.建立GO/AO物件
        2.找形參和變數宣告,將變數和形參名作為AO屬性名,值為undefined
        3.將實參值和形參統一

        4.在函式體裡面找函式宣告,值賦予函式體

以此為例:

  再次函式中我們來進行預編譯:
      1.建立AO物件:我們隱式的在函式中建立了一個AO的物件來盛放函式中的變數,此時物件中並沒有值;

       2.找形參和變數宣告,將變數和形參名作為AO屬性名,值為undefined:我們在第二個過程中需按照變數和形參

                           

      3.將實參值和形參統一:此時將實參帶入函式中由於在函式外 f(1),因此AO中a = 1

                 

    4.在函式體裡面找函式宣告,值賦予函式體:由於在函式中有 function a() {} ,這一函式因此此時AO中 a = function a() {}

                           

在進行完預編譯後此時若執行函式則會以AO為基礎對函式中的變數進行賦值:此時函式中有兩次列印一次在函式開頭,一次在函式為a賦值之後

再賦值前由於AO中值不變因此a所打印出的值為 function a() {}

在賦值後AO中a = 123,所以此時打印出的值為123

相關推薦

js編譯四部曲

再次複習了一下作用域和預編譯的知識仔細的看了下老師視訊和部落格 學習到了一些關於預編譯和作用域的知識和大家分享一下! 眾所周知javascript是解釋性語言,主要特點為解釋一行執行一行。 而在js執行時會進行三件事:1語法分析  2.預編譯  3.解釋執行     

typeof、搖樹優化、js編譯

顯示 obj 表達 string defined 原始的 刪除 執行 undefined typeof:    typeof用以獲取一個變量或者表達式的類型,一元運算符 null:空、無。表示不存在,當為對象的屬性賦值為null,表示刪除該屬性 undefined

js編譯

函數表 兩個 oba 引用 con 實參形參 表達 var 函數形參 我們都知道js執行遵循兩個規則 1.函數聲明整體提升 2.變量 聲明提升 其實還有一點最重要的就是預編譯,預編譯往往發生在函數執行前,了解預編譯,對我們理解函數執行非常關鍵。 預編譯的前奏 1.

js編譯規則

func test pan var 統一 變量 gpo color undefine 1.創建一個AO對象 2.找形參、變量聲明,把形參、變量聲明的名作為AO對象的屬性名,值為undefined 3.實參形參相統一,即把與形參相對應的實參的值賦給AO對象中相應的屬性 4.找

js編譯原理

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>js預編譯原理</title> </head> <body> <scrip

js---編譯

js作為解釋型語言執行的時候分為三步 1.通篇掃描,有沒有基礎語法錯誤。 2.預編譯,發生在函式執行前一刻。 3.解釋執行。 預編譯的步驟: 1.建立AO(活動物件,即作用域,執行期上下文,任何函式每次執行都會產生屬於當前執行的自己的獨一無二的AO,同一個函式執行時會產生不同的AO,a()

關於js編譯、宣告提前的有趣現象

關於js,大家都知道js是一門單執行緒的解釋性語言,解釋性語言就是指一句一句執行的語言。 js在執行前會先預編譯下,簡單點說就是掃描js程式碼,對要宣告變數的宣告,提前的提前! 接下來就講一下預編譯的

js編譯和函數執行

scrip 詞法 創建 java rip function object 變量賦值 一次 javascript 執行過程 1.語法檢測(有沒有基本的語法錯誤,例如中文,關鍵字錯誤...)2.詞法分析(預編譯) (1)創建全局GO(global object)對象

重溫JS編譯的四個步驟

JS是解釋型語言,執行過程分三步: 一、語法分析(檢查程式碼是否存在語法錯誤); 二、預編譯(程式碼執行之前,在記憶體中開闢空間,存放變數與函式);   三、解釋執行(執行JS程式碼); 理解預編譯的過程,對於理解作用域鏈、閉包、this指向、原型鏈至關重要,它們是相輔相成的。

js編譯AO物件及GO物件

簡單談一下js的預編譯過程。 function test(a,b){     console.log(a)     var a=123;      function a(){}     console.log(b)     var b=234;     console.lo

JS編譯面試題 其一

<script> var x = 1, y = z = 0; function add(n) { n = n+1;   } y = add(x); //2 function add(n) {

js編譯、全局變量、局部變量相關知識

所有 func var 等價 局部變量 () 全局 log not 1、未聲明的變量就賦值, 此變量歸全局變量window對象所有 console.log(a); //a is not defined a=10 console.log(a); //10 等價於 co

js編譯

不執行 style 生成函數 函數聲明 nbsp 全局變量 bsp 形參 函數名 js執行的三步:語法檢查,預編譯,解釋執行. js預編譯前:window對象==全局 1.任何位置上的變量未聲明直接賦值是全局變量,發到window裏 2.在函數外聲明的變量也是全局,放到wi

js編譯

預編譯過程 1.建立AO物件 2.找形參和變數宣告,將變數和形參名作為AO屬性名,值為undefined 3.將實參值和形參統一 4.在函式體裡面找函式宣告,值賦予函式體 程式碼: <!DOCTYPE html> <html lang="en"> <head&g

js中的編譯和作用域鏈

JavaScript執行三部曲 指令碼執行js引擎都做了什麼呢? 語法分析 預編譯 解釋執行 1.語法分析分析語法是不是錯了 2,在語句執行的時候會進行預編譯 3.在編譯完了進行語句執行 下面就是編譯的主要步驟 三。預編譯的過程(分四步): 1.

js復習,編譯

函數 lob 暗示 glob 所有 整體 bsp 提升 ply 註意:函數聲明整體提升、變量 聲明提升 1、imply global 暗示全局變量:即任何變量,如果變量未聲明就賦值,此變量就為全局對象所有 ==> eg: a = 122;==> eg:var

js作用域鏈和編譯

 js引擎執行分為兩步,預解析 程式碼執行 (1)預解析: js引擎會拿js裡面所有的var還有 function 提升到當前作用域的最前面 (2)程式碼執行:按照程式碼書寫的順序從上往下執行 預解析分為:變數預解析(變數提升)和函式預解析(函式提升)

ANPM-Apache_httpd-Nginx-PHP-MySQL 官方編譯包源(Pre-Built Packages Repository)收集

apache httpd nginx php mysql ANPM-Apache_httpd-Nginx-PHP-MySQL 官方預編譯包源(Pre-Built Packages Repository)收集Apache_httpdNginxhttp://nginx.org/en/linux

js解析

想要 javascrip 解析器 參數傳遞 java 字符 參數 被占用 lar 1. 定義 預解析:在當前作用域下,js運行之前,會把帶有var和function關鍵字的事先聲明,並在內存中安排好。然後再從上到下執行js語句。 預解析只會發生在通過var定義的變量和fun

IIS編譯提升載入速度

microsoft -i for 感覺 初始化 重新 -m 選擇 req 當我們把站點部署在IIS7或IIS6S的時候,每當IIS或是ApplicationPool重新啟動後,第一次請求站點反應總是非常慢。原因大家都知道(不知道能夠參考這個動畫說明ASP.NET網