《從規範看ECMAScript》是筆者將要寫的一系列文章+筆記,目的是從規範底層來看ECMAScript的各種行為(特色or異常)。
所有文章都在Github上,歡迎star、watch。
參考的規範是ECMASCript2018即ES9,地址?。
因為ES9是ES正式的最新版本,於2018年六月釋出。而ECMAScript2019?目前的狀態還是draft(大概19.6轉為正式)。雖然變動不會太大,還是以穩定的版本為準吧。
本文還參考了zhoushengmufc的中文版本ES6(此中文版本未譯全)。在這裡,筆者還要推薦一個Github的專案:engine262?。此專案按照規範實現了一個標準的ES的直譯器。(是真的標準,基本完全符合規範裡的演算法步驟,除錯除錯對理解規範的執行時語義更有幫助。)
筆者的文章主要是對ES執行時語義的分析,所以關於其靜態語義講的不多。
如果你想完整的閱讀規範,閱讀之前可以先看看一個大神寫的如何閱讀ES,上面提到的engine262也有他的參與。
本文主要介紹規範1~5章,是對ES的總覽和規範裡的記法約定。
介紹
ES1th釋出於1997年6月,ES2th釋出於1998年6月,主要是對第一版的格式修正。
ES3th引入了正規表示式,更好的字串處理,新的控制語句,try/catch
異常處理,更嚴格的錯誤定義,數字輸出的格式。釋出於1999年12月。
ES3之後ES被全球資訊網所採用,被大部分瀏覽器所支援。但是由於關於語言的複雜性出現分歧,ES4th沒有完成。
ES5th增加了一些特性,例如嚴格模式、訪問器屬性、JSON的支援等,釋出於2009年12月。ES5.1對ES5進行了微小的修改,釋出於2011年6月。
ES6th釋出於2015年6月,實際上ES6的集中發展在2009年,並且在1999年出版第三版之前,就進行了大量的實驗和語言增強設計工作,可以說ES6是十五年努力的結果。發展目標包括更好地支援大型應用程式、庫建立以及將ECMAScript用作其他語言的編譯目標。
其主要改進為:模組、類宣告、詞法作用域、迭代器和生成器、promise
非同步程式設計、結構模式、尾呼叫。擴充套件了ECMAScript內建庫,以支援額外的資料抽象,包括map
、set
、二進位制數值陣列,以及對字串和正規表示式中Unicode補充字元的額外支援。
ES7th新增了指數運算、Array.prototype.includes
。另外從ES7開始ES釋出就是一年一更了(我根據規律猜的?)。
ES8th引入了Async
、共享記憶體、Atomics
、庫增強、Bug修復。
async
函式提供了promise-returning
函式,增強了非同步程式設計體驗。
共享記憶體和Atomics
引入了一種新的記憶體模型,允許多代理程式使用原子操作進行通訊,即使在並行處理器上也能確保定義良好的執行順序。(暫時不太懂)
還增加了Object.values
, Object.entries
, 和 Object.getOwnPropertyDescriptors
。
本規範(ES9th)通過非同步迭代器協議和非同步生成器引入對非同步迭代的支援。還引入了四個新的正規表示式特色,還有物件屬性的rest引數和擴充套件運算子支援。
概述
ECMAScript是一種物件導向的程式語言,用於在宿主環境中執行計算和操作計算物件。
ECMAScript最初被設計成一種Web指令碼語言,提供了一種機制來使瀏覽器中的網頁更加有趣,並作為基於Web的客戶端-伺服器體系結構的一部分來執行伺服器計算。
ECMAScript現在用於為各種宿主環境提供核心指令碼功能。
這一節有用的就這些,其中宿主環境指瀏覽器或者Node環境等。
Web Scripting
瀏覽器端
Web瀏覽器為客戶端計算提供了ECMAScript宿主環境,例如:視窗物件、選單、彈出視窗、對話方塊、文字區域、連結、框架、瀏覽歷史、cookie、和輸入/輸出。
此外,主機環境提供了一種將指令碼程式碼附加到事件的方法,例如:焦點改變、滑鼠動作等等事件。指令碼程式碼對使用者互動起反應,不需要主程式。
在瀏覽器端ES主要為了處理使用者與瀏覽器之間的互動。
服務端
Web伺服器為了伺服器端計算提供了一個不同的宿主環境,包括請求、檔案IO等等。
每個支援ECMAScript的Web瀏覽器和伺服器都提供自己的宿主環境,以完成ECMAScript執行環境。
ECMAScript總覽
ES是基於物件的,基本語言和宿主工具都是由物件提供,ES程式是一組通訊物件。
物件是一系列屬性property的集合。每個屬性的特性attribute決定了屬性行為。例如其writable
決定其是否可寫,configurable
決定其是否可配置,等等。
屬性是一個容納其他物件、原始值、函式的容器。
原始值(primitive value)有六種型別:Undefined、Null、 Boolean、Number、String、Symbol。
函式(function)是可呼叫(callable)物件。通過屬性與物件關聯的函式稱為方法(method)。
ECMAScript定義了一組內建物件,這些物件完善了ECMAScript實體的定義。
這些內建物件有
全域性(Global)物件;
維持語言執行時語義的基礎的物件: Object
、 Function
、Boolean
、Symbol
和各種Error
物件;
表示和操控數值的物件:Math
、Number
、和Date
;
用於處理文字物件:String
和 RegExp
;
值的索引集合的物件:Array
,和九種型別的陣列,其元素都具有特定的數值資料表示形式;
鍵的集合的物件:Map
、Set
;
結構化資料的物件:JSON
、ArrayBuffer
、SharedArrayBuffer
和 DataView
;
控制抽象的物件:生成器函式、Promise
;
反射物件:Proxy
、Reflect
。
ECMAScript定義了一系列內建操作符:* / + - >> 等等。
大型ES程式支援模組(Module)化,允許程式被分成多個語句和宣告序列。 每個模組顯式地標識它使用的需要由其他模組提供的宣告,以及它的哪些宣告可供其他模組使用。
這節大概講了下ES的型別,內建物件。關於其型別,在第六章會詳細講述。
物件
ES 物件並不是完全基於類的。 可以通過各種方法,例如字面量定義或構造器(constructor)來建立物件,並對其分配屬性。
每個構造器都是一個函式,都有一個原型屬性,用來實現基於原型的繼承和屬性共享。
構造器建立的物件有一個被稱作物件原型的隱式引用, 指向構造器的prototype
屬性。
原型可以具有對其原型的非空隱式引用,這就是原型鏈。
當引用物件中的屬性時,該引用指的是原型鏈中包含該名稱的屬性的第一個物件中該名稱的屬性。首先檢查直接物件的這種屬性; 如果該物件包含命名屬性,則引用該屬性; 如果該物件不包含命名屬性,則接下來檢查該物件的原型。
(上面這張圖大家應該看得懂,我就不解釋了。看不懂的話本文可能不適合你,再瞭解瞭解JS再來看吧。)
在基於類的面嚮物件語言中,通常狀態由例項承載,方法由類承載,繼承僅具有結構和行為。 在ECMAScript中,狀態和方法由物件承載,而結構,行為和狀態都是繼承的。
嚴格模式
ES還提供了嚴格模式,嚴格變體排除了常規ECMAScript語言的某些特定句法和語義特徵,並修改了某些特徵的詳細語義。
略述,詳細內容?
術語和定義
這小節定義了許多術語,例如型別、原型、原始值、構造器等,還有string
、number
這些值的範圍等等,詳細內容?。
講幾個不好理解的術語,物件的四種型別:
ordinary object
普通物件:物件具有所有物件支援的基本內部方法。exotic object
怪異物件:沒有一個或多個基本內部預設方法的物件。(任何不是普通物件的物件都是非普通物件。)standard object
標準物件:其語義由本規範定義。標準物件可以是普通物件,也可以是怪異物件。built-in object
內建物件:按照ECMAScript實現的物件。標準內建物件在本規範中定義。 ECMAScript實現(例如JS、Node)可以指定和提供附加種類的內建物件。 內建建構函式是一個內建物件,也是一個建構函式。所有的標準物件都是內建物件。
舉例說明一下:
// 普通物件就是普通物件嘍
let ordinary_obj = {
a: 'test',
b: 1
}
// 怪異物件就是非普通物件,例如函式的引數args、陣列物件、字串物件等
let standard_object = new String('lalala')
// 標準物件就是本規範定義的例如
let standard_obj = new Array()
// 內建物件就是宿主環境內建的物件例如
let built_in_obj = console
複製程式碼
這些不太重要,就不細說了(因為我也不太懂?)
本規範章節組織
第五章:規範的記法約定。
第六-九章:定義了ES程式執行的執行環境。
第十-十六章:定義了實際的ES程式語言,包括句法編碼、執行時語義等。
第十七-二十六章:定義了ES標準庫,包括ES程式執行時可用的所有標準物件。
第二十七章:描述了SharedArrayBuffer
支援的記憶體訪問的記憶體一致性模型以及Atomics
物件的方法。
記法約定
這章主要是一些編譯原理的知識。不做過多探討,有興趣可以看?。
語法和詞法
上下文無關法
上下文無關文法由多個產生式(production)組成.每個產生式具有作為其左側的非終結符號以及右側零個或多個非終結符號和終結符,對於每個語法,終端符號從指定的字母表中繪製。
鏈產生式(chain production)是在其右側具有一個非終端符號以及零個或多個終端符號的產生式。
從由單個區分的非終止符(稱為目標符號)組成的句子開始,給定的上下文無關語法規定了語言,即可能的 可以由右側序列中的任何非終端,重複替換非終止符是左側的終端符號的序列。
來舉個:chestnut::
ArrayLiteral: [Elision]
[ElementList]
[ElementList, Elision] ElementList: Elision AssignmentExpression
Elision SpreadElement
ElementList, Elision AssignmentExpression
ElementList, Elision SpreadElement Elision: ,
Elision , SpreadElement: ...AssignmentExpression
上面是定義陣列字面量的產生式(省略了很多引數,加上引數後使得語法更加完備)?。其中斜體字就是非終結符,意味著還可以再往下推導;非斜體字就是終結符,意味著不能再推導了。
從上自下,ArrayLiteral代表一個陣列字面量,其有三種可能的表示方式,這三種又可以往下推直到不能再推導為止。
例如[]
就屬於[Elision],[1,2]
就屬於[ElementList]。
這樣的描述覆蓋了所有ES裡的陣列字面量的語法形式。
演算法約定
在描述ES語言語義時,使用了一些演算法步驟,大家可以將其看作虛擬碼。
很簡單的(假的?,有些我也不太懂,不敢亂講。不過不影響理解執行時語義,所以也不多說了。)
這篇就完了,感覺沒講啥,好多我不關心的都沒講,有點慚愧。?
下一篇就正式開始接觸ES了,講講ES的資料型別和值(包括語言的和規範的)還有一些基本的抽象操作(用於描述ES的語義)。