JavaScript 核心觀念(1)-執行環境與作用域-JavaScript 運作方式
前言
第一篇將會來了解 JavaScript 的運作模式,
JavaScript 運作方式
在一開始這邊是有一個重點要先說明的,首先「JavaScript 是無法直接被電腦執行的,而是必須透過一個中間人,也就是所謂的轉譯器,將相關的指令轉換成電腦能懂的指令」。
舉例來講:
1 | var a = 1; |
這一段是必須先被轉譯器給轉譯才能夠被電腦執行。
直譯語言 Interperted language
那什麼是直譯語言呢?JavaScript 就是一個直譯式語言,所謂的直譯式語言就是,他會直接編譯的語言(廢話)。
直譯語言的另一種就是編譯式語言,而編譯式語言最大特色在於,在我們撰寫程式碼的同時,他已經在預先編譯,所以當遇到問題時我們就可以預先除錯,那麼這就是編譯式語言的好處,通常來講效能也會比較好。
那麼所謂的預先編譯是什麼意思,又為什麼預先編譯會效能較能好?其原因在於我們在撰寫程式碼時,程式碼就已經被編譯成機器碼(也就是電腦可以懂的指令),所以可以直接被執行,而直譯式語言最大差別在於,必須先一條一條將程式碼讀取出來再轉換成機器碼,所以相較之下編譯式語言的效能是比較好的。
而比較代表性的語言有
- Objectlive-C
- C++
- C#
…
等等
可是編譯式語言的壞處在於,你在開發時彈性會比較小且通常開發的速度以及 Debug 的時間是比直譯式語言較長的。
那麼回過頭來講講直譯式語言,在前面有講到,直譯式語言與編譯式語言最明顯的差異在於直譯式語言必須先一條一條將程式碼讀取出來並透過直譯器轉換成機器碼才能夠被運作,所以通常來講直譯式語言的錯誤訊息都是直接呈現於開發環境上,舉例來講 JavaScript 就是直接呈現在瀏覽器的 console Tools。
那麼直譯式語言的好處在於開發速度是比較快速且較彈性的,舉例來講 JavaScript 中我們可以不用預先定義型別,而是透過直譯器來動態辨別型別。
JavaScript 直譯器轉換過程
在前面有講到直譯式語言會一條一條將程式碼讀取出來透過直譯器轉換成機器碼,而 JavaScript 也是相同的,JavaScript 在運行時他會一個一個字去分析並解析出相對的機器碼,舉例來講:當你輸入 func
此時直譯器預期接下來你第五個~第八個單字會是 tion
,然後組合成一個 function
,而這個過程就是所謂的語法基本單位化(Tokenizing),所以由此可知直譯器是會逐行逐字的去分析。
接下來當語法基本單位化完畢就會進入抽象結構樹 AST(Abstract Syntax Tree) 來講整個程式碼來定義完成,最後在將程式碼轉換成機器碼。
在課程上也有介紹使用一個 Esprima 的小工具來了解何謂語法基本單位化及抽象結構樹。
首先我們可以先在 Esprima 輸入以下程式碼
1 | function SayHi() { |
透過旁邊的 Token 分頁標籤我們可以看到程式碼都被分析成一個一個類似物件的結構,而這就是所謂的語法基本單位化(Tokenizing)。
你可能會看到 type 會有這些選項
Keyword
(關鍵字)Identifier
(標識符,又稱為識別碼)Punctuator
(符號)String
、Number
(型別)
但是在這邊要注意,在語法基本單位化時,他還不知道 function
是宣告一個函式,他只是先將字詞解析出來而已。
此外若你勾選下方「Index-based range」及「Line and column-based」你都可以看到相關的索引及行數。
在這邊有一個意外的插曲,不知道為什麼 Tree 不能看,所以就只好擷取影片中的畫面。
透過這過程我們可以了解到 JavaScript 的直譯器,是在 Tree 的階段才開始正式的了解每一個字詞的意義,例如 var
代表宣告變數等,但是這邊 JavaScript 並還沒有開始真正的執行,只是了解他的字詞而已,真正的執行是在代碼生成的時候,但每一個執行環境的不同,所以執行的結果就會跟著不同,概念就像是 Node.js 環境下以及瀏覽器的環境差異。
這邊最主要的重點在於 抽象結構樹 AST(Abstract Syntax Tree) 時,程式碼是還沒有被運行的,實際運行是在代碼生成的時候。