JavaScript 簡史

zcfy發表於2017-02-08

  JavaScript 毋庸置疑是當今最重要的語言之一。Web 的興起已經把 JavaScript 帶到一個前所未有的地步。下面我們來看看 JavaScript 在其短短歷史中是如何演變的,以及它在走向何處。請繼續讀下去!


 這一切都開始於九十年代

  一切都發生在 1995 年 5 月到 11 月這六個月內。網景通訊公司在早期的 Web 中擁有強大的地位。它的瀏覽器 Netscape Communicator,作為第一款流行 Web 瀏覽器 NCSA Mosaic 的競爭對手,正獲得廣泛認同。網景是由 90 年代早期參與 Mosaic 開發的同一夥人創立的,而現在,有了錢和自主性,他們就有了尋求進一步擴充套件 Web 的途徑所需的自由。而這種自由催生了 JavaScript。

Netscape Logo

  網景通訊的創始人及前 Mosaic 團隊的成員 Marc Andreessen 預見到 Web 需要某種方法變得更動態。動畫、互動和其它形式的小動畫應該是未來 Web 的一份子。所以 Web 需要一種能與 DOM 互動(不是跟你現在看到的這樣一成不變)的小指令碼語言。不過,這種指令碼語言不應該面向大佬開發者,以及在軟體工程方面有經驗的人們——在當時這是一種重要的戰略呼聲。當時 Java 也在興起,並且 Java applets 很快就要成為現實。所以這個用於 Web 的指令碼語言需要迎合另一群受眾:設計師。實際上,那時 Web 是靜態的。HTML 依然年輕,並且足夠簡單,非程式設計師也很容易學得會。所以,要讓 Web 變得更動態,不管是瀏覽器的哪一部分,都應該讓非程式設計師容易理解。這樣 Mocha 的想法就誕生了。Mocha 要成為用於 Web 的一種指令碼語言,它必須是簡單、動態的,並且讓非程式設計師容易理解。

Marc Andreessen

  此時,JavaScript 之父 Brendan Eich走上了歷史舞臺。網景通訊公司僱傭 Eich,是讓他開發一種 “用於瀏覽器的 Scheme。Scheme 是一種 Lisp 的方言,語法很簡單,它動態而強大,並且本質上是函式式的。而 Web 需要類似這樣的語言:語法容易掌握;動態的,以減少程式碼,加快開發;並且強大。Eich 看到有機會可以從事自己喜歡的事情,於是就入夥了。

Brendan Eich

  當時,迫於壓力,必須儘快趕出一個工作原型。當時原名為 Oak 的 Java 語言正開始推動。Sun Microsystems 正大力推進 Java,網景通訊公司即將與他們達成一項協議,讓 Java 可以用在瀏覽器上。那麼為什麼要開發 Mocha(JavaScript 早期的名字)呢?為什麼已經有了 Java,卻還要開發一個全新的語言呢?當時的想法是,Java 不適合 Mocha 的目標受眾:測試指令碼編寫人員、業餘愛好者、設計師。對於用在瀏覽器這個角色上來說,Java 確實太大太重了。所以當時他們的想法是讓 Java 用於大型專業級元件開發;而 Mocha 將用於小型指令碼任務。也就是說,Mocha 命中註定就是 Java 的指令碼同伴,在某種程度上類似於 Windows 平臺上 C/C++ 和 Visual Basic 之間的關係。

與此同時,網景的工程師開始詳細地研究 Java。他們甚至開始開發自己的 Java 虛擬機器。不過,這個虛擬機器很快被否決,因為它從來就沒有實現與 Sun 的虛擬機器的完美一致。

  此時有很多來自於內部的壓力,要儘可能快地選擇一門語言。Python、Tcl 以及 Scheme 本身都是可能的候選。所以,Eich 必須快。不過,他比別人有兩個優勢:可以自由挑選適合的特性集、可以直達拍板的人。不幸的是,他也有一個大的劣勢:沒有時間。必須要做出很多重要的決定,而做出決定的可用時間又很短。JavaScript,即 Mocha,就是在這種背景下誕生的。幾周之內,一個工作原型就推出了,然後就被整合到 Netscape Communicator 中。

  於是,本應是用於瀏覽器的 Scheme,現在就大相徑庭了。與 Sun 達成協議的壓力,以及讓 Mocha 變成 Java 的指令碼同伴,束縛住了 Eich 的手腳。新語言需要採用類似 Java 的語法,對於很多常用語還採用了熟悉的語義。所以 Mocha 一點也不像 Scheme。它表面上看像是一種動態的 Java,實際上卻是Scheme 和 Self 的早產私生子,但長的像 Java。

  1995 年 5 月, Mocha 的原型被整合到 Netscape Communicator 中。很快,它被重新命名為 LiveScript。當時,"live" 這個單詞只是為了營銷方便。1995 年 12 月,網景通訊公司和 Sun 達成協議:Mocha/LiveScript 將被重新命名為 JavaScript,它將會作為瀏覽器中小型客戶端任務的一種指令碼語言,同時 Java 將會被提升為一種更大的、開發富 Web 元件的專業工具。

  第一版的 JavaScript 敲定了該語言中很多現在知名的特性,特別是其物件模型以及函式式特性在此版本中已經出現了。

如果當時 Eich 未能按時趕出一個工作原型,很難說會發生什麼。其他可選方案一點也不像 Java。Python、Tcl 和 Scheme 都與 Java 大不相同。對於 Sun 公司來說,很難接受一個與 Java 如此不同的同伴語言,或者在歷史和開發上比 Java 本身早的語言。另一方面,Java 很長一段時間是 Web 的一個重要部分。如果 Sun 從沒有過這樣的地位,網景可能會在挑選這樣一個語言上有更多的自由。這是肯定的。不過,如果就算網景自己內部能控制和開發,它會不會選擇採用外部的解決方案呢?我們將永遠不會知道。

  不同的實現

  當 Sun 和 Netscape 達成協議,將 Mocha/LiveScript 的名稱改為 JavaScript 時,有個大問題被提出來了:其他實現會怎麼辦?實際上,儘管 Netscape 很快成為了當時首選的瀏覽器,不過微軟也正在開發 Internet Explorer。從最開始,JavaScript 就帶了使用者體驗如此大的差異,競爭瀏覽器沒辦法,只能自己也整一套 JavaScript 的實現。此時(並且很長一段時間),Web 標準還不強大。所以微軟實現了自己版本的 JavaScript,叫做 JScript。從名稱中去掉 “Java”,是為了避免潛在的商標問題。不過,JScript 不僅僅是名稱上的不同。它在實現上也略有不同,特別是與某些 DOM 函式有關的實現上有所不同,由此產生的影響一直波及到多年之後的未來。JavaScript 大戰還發生除了名稱和時間表之外的更多方面上,而它的怪癖正是這些大戰打來的創傷。JScript 的第一個版本包含在 1996 年 8 月釋出的 IE 3.0 中。

  網景的 JavaScript 實現也採用了一個內部名稱。和 Netscape Navigator 2.0 一起釋出的版本被稱為 Mocha。在 1996 年秋天,Eich 為了償還匆忙推出它所欠下的技術債,將 Mocha 的大部分重寫為一個更乾淨的實現。這個新版本的網景 JavaScript 引擎叫做 SpiderMonkey。SpiderMonkey 現在依然是 Netscape Navigator 的孫子 Firefox 中 JavaScript 引擎的名稱。

  有好幾年,JScript 和 SpiderMonkey 是主要的 JavaScript 引擎。二者共同實現的功能(並非總是相容)會定義接下來幾年中 Web 的樣子。

  主要設計特點

  儘管 JavaScript 是倉促之作,不過有幾個強大的特性在一開始就具備了。這些特性將 JavaScript 定義為一門語言,儘管有各種怪癖,依然讓它能獨樹一幟。

是使用一門已有的語言,還是發明一門新的語言,這也不是我能決定的。來自高層工程管理人員的強制命令是這門語言必須“看起來像 Java ”。這實際上也就把 Perl、Python、 Tcl 以及 Scheme 這些已有的語言排除掉了。後來,在 1996 年,John Ousterhout 在給 Tk 做宣傳時還感嘆說,Tcl 錯過了這樣一個很好的機會。我並非驕傲,只不過是很高興我選擇 Scheme 式的一等函式以及 Self 式(儘管很怪異)的原型作為主幹。至於 Java 的影響,主要是把資料分成基本型別和物件型別兩種(比如字串和 String 物件),以及引入了Y2K 日期問題,這真是不幸。 - Brendan Eich 的部落格:關於流行

  類 JAVA 的語法

  儘管讓 JavaScript 語法接近 Java 並非初衷,不過市場力量讓它變成了這樣。退一步想,即使採用與 Java 不同的語法可能會讓實現某些特性更為方便,但是不可否認,採用熟悉的語法更有助於 JavaScript 的普及。

  將如下的 Java 示例:

public class Sample {
  public static void main(String[] args) {
    System.out.println("Hello world!");
    try {
      final MissileSilo silo = new MissileSilo("silo.weapons.mil");
      silo.launchMissile(args[0]);
    } catch(Exception e) {
      System.out.println("Unexpected exception: " + e);
    }
  }
}

  與如下(現代) JavaScript 示例做比較:

console.log('Hello world');
try {
  const silo = new MissileSilo('silo.weapons.mil');
  silo.launchMissile(process.argv[0]);
} catch(e) {
  console.log('Unexpected exception' + e);
}

  函式作為一等物件

  在 JavaScript 中,函式只是又一個物件型別。它們可以像任何其它元素一樣傳遞,可以被繫結到變數。在稍後版本的 JavaScript 中,函式甚至可以被丟擲為異常。這個特性很有可能是在 JavaScript 開發時受到 Scheme 強烈影響的結果。

var myFunction = function() {
  console.log('hello');
}
otherFunction(myFunction);
myFunction.property = '1';

  通過讓函式變成一等物件,某些函數語言程式設計模式才成為可能。例如,較新版本的 JavaScript 利用了某些函式式模式:

var a = [1, 2, 3];
a.forEach(function(e) {
  console.log(e);
}); 

  這些模式已經被成功用於很多庫,比如 underscoreimmutable.js

  基於原型的物件模型

  儘管基於原型的物件模型是通過 JavaScript 得以流行的,不過它卻是在 Self 語言中首次引入。Eich 對這種模型有種強烈的偏好,它足夠強大,能夠模仿像 Java 或 C++ 這種基於 Simula 的語言中的更傳統的方式。實際上,JavaScript 之後的版本中實現的類,也只不過是在原型系統之上的語法糖。

  JavaScript 的原型靈感來自於 Self,而 Self 的設計目標之一就是要避免 Simula 風格的物件的問題。特別是,在 Simula 的方式下,類和例項之間的對立被看到是很多固有問題的誘因。有人認為,因為類為物件例項提供某種原型,隨著程式碼演變和逐漸變大,就越來越難讓這些基類適應不可預料的新需求。通過將例項作為新物件構建的原型,這種限制就被克服了。因此,原型的概念是:一個通過提供自己的行為,填補新例項的空白的例項。如果一個原型被認為不適合於一個新物件,那麼它只需要被克隆和修改,而不會影響所有其它子例項。這在基於類的方式中是挺難做到的(即,修改基類)。

function Vehicle(maxSpeed) {
    this.maxSpeed = maxSpeed;
}

Vehicle.prototype.maxSpeed = function() {
    return this.maxSpeed;
}

function Car(maxSpeed) {
    Vehicle.call(this, maxSpeed);
}

Car.prototype = new Vehicle();

  原型的威力讓 JavaScript 變得超級靈活,引發了很多帶有自己物件模型的庫的開發。一個流行的庫 Stampit 就重度使用了原型系統,採用在基於類的傳統方法下不可能的方式,來擴充和操作物件。

  原型讓 JavaScript 表面上看起來簡單,但是給庫的作者帶來了自主權。

  大怪癖:基礎型別與物件

  也許在匆忙開發的 JavaScript 中,最大的錯誤之一是某些行為類似的物件有不同的型別。例如,字串字面量("Hello world")的型別與 String 物件(new String('Hello world'))的型別就是不相同的。這就讓我們有時候不得不採用不必要的、容易混淆的型別檢查。

> typeof "hello world"
< "string"

> typeof new String('hello world')
< "object"

  然而,在 JavaScript 歷史中,這只是個開始。它的倉促開發真真切切地導致了一些設計失誤。不過,發明一種用於動態 Web 的語言的優勢不能耽擱,其它的一切只有交給歷史了。

餘下的是逆襲的、殘酷的歷史。JS 在客戶端戰勝了 Java,競爭的只有 Flash,而 Flash 支援 JS 的後代 ActionScript - Brendan Eich 的部落格:流行

  追憶往事:看看 Netscape Navigator 2.0 和 3.0

  JavaScript 的第一個公開發行版被整合到 1995 年釋出的 Netscape Navigator 2.0 中。多虧了虛擬化的奇蹟和過時軟體網站,我們現在還可以重現那些時刻!

Netscape Navigator 2.01 Gold

  不幸的是,那時很多 JavaScript 的基礎特性並不能用。匿名函式和原型鏈這兩個最強大的特性就遠遠沒有今天這麼完善。不過,這些特性已經是該語言設計的一部分,會在後面幾年中正確實現。需要指出的是,在這個發行版中的 JavaScript 直譯器被認為是處於 alpha 狀態。

  Netscape Navigator 2

  幸運的是,一年後,1996 年釋出的 Netscape Navigator 3.0 已經有很大變化:

  Netscape Navigator 3

  注意視訊中的錯誤是如何給我們發生什麼事情的更多資訊。這讓我們推測直譯器以一種特殊的方式對待 prototype 屬性。於是我們嘗試用基礎的 Object 例項來替換物件,這樣我們之後就可以修改該物件。嗯,好了,搞定了!至少在某種程度上。test 函式內的賦值貌似什麼都沒做。很顯然,還有很多工作需要去做。儘管如此,這個狀態的 JavaScript 對於很多工是可用的,並且它已經開始流行了。

  像正規表示式、JSON 和異常等特性此時依然不能用。在接下來的幾年中,JavaScript 會迅猛發展。

 ECMAScript: JavaScript 標準

  JavaScript 公開發布後的第一次重大改變是以 ECMA 標準化的形式出現。ECMA 是 1961 年成立的一個行業協會,該協會只從事資訊和通訊系統的標準化。

  JavaScipt 的標準化工作始於 1996 年 11 月。標準號是 ECMA-262,負責的委員會是 TC-39。這時候,JavaScript 已經是很多頁面的流行元素。這份1996 年的新聞稿 說採用 JavaScript 的頁面數量已達 300,000。

JavaScript 和 Java 是開發 Internet 和 Intranet 應用程式的 Netscape ONE 平臺的基礎技術。自去年引入它們的很短一段時間內,新語言快速被開發者接受。根據 www.hotbot.com 統計,在當今網際網路上有 175,000 個新 Java 小程式和超過 300,000 個使用 JavaScript 的頁面。- Netscape 新聞稿

  對於這樣一個年輕的語言來說,標準化是一個重要的步驟,不過依然是一個重大的號召。它將 JavaScript 開放給更廣泛的受眾,並且給其它潛在的實現者在語言進化上的發言權。它還充當了約束其它實現者的用途。那時候,人們擔心微軟或者其它人會偏離預設的實現太遠,從而導致分裂。

  由於商標的原因,ECMA 委員會不能用 JavaScript 做名字,而其它名稱也有很多人不喜歡。所以經過幾輪磋商後,決定這個用標準來描述的語言將被叫做 ECMAScript。現在,JavaScript 只是 ECMAScript 的商業名稱。

  ECMAScript 1 和 2:標準化之路

  第一個 ECMAScript 標準是基於 Netscape Navigator 4 釋出的 JavaScript 版本,它依然缺失重要的特性,比如正規表示式、JSON、異常,以及內建物件的重要方法。不過,在瀏覽器中它工作得不錯。JavaScript 正開始變得越來越好。1997 年 6 月,版本 1 釋出了。

  Netscape Navigator 4

  注意,視訊中那個簡單的原型和函式測試現在可以正常工作了。在 Netscape 4 中很多工作已經在幕後完成了,而 JavaScript 從受益良多。現在我們的示例基本上可以與任何當代瀏覽器執行的一樣了。這對於 JavaScript 第一次釋出成一個標準來說,是一個很好的局面。

  標準的第二版 ECMAScript 2 的釋出是用來糾正 ECMA 和 JavaScript ISO 標準(ISO/IEC 16262)之間的不一致性的,所以語言沒有做任何改動。這個版本釋出於 1998 年 6 月。

  此版本的 JavaScript 的一個有趣的怪癖是,在編譯時沒有被捕獲的錯誤(這通常是留作為未確定的)交給直譯器任意決定如何處理。這是因為異常還不是該語言的一部分。

  ECMAScript 3:第一次大變動

  ECMAScript 2 後工作在繼續,對該語言的第一次大變更出現了。這個版本帶來了:

  • 正規表示式

  • do-while 塊

  • 異常和 try/catch 塊

  • 更多有關字串和陣列的內建函式

  • 格式化數字輸出

  • ininstanceof 運算子

  • 更好的錯誤處理

  ECMAScript 3 釋出於 1999年 12 月。

  這個版本的 ECMAScript 流傳甚廣。它被當時的所有主流瀏覽器所支援,而且多年後一直支援。即使到了今天,有些轉譯器依然可以在產生輸出時,以這個版本的 ECMAScript 為目標。這讓 ECMAScript 3 成為了很多庫的基準目標,即使後來版本的標準釋出了也是如此。

  即使 JavaScript 越來越流行,它依然主要是一種客戶端語言。不過,它很多新特性讓它離打破這種牢籠更近。

  2000年 11 月,Netscape Navigator 6 釋出。這個版本是對過去版本的重大修訂,支援 ECMAScript 3。大約在一年半後,Firefox 釋出。它是一個基於 Netscape Navigator 程式碼庫的精簡版瀏覽器,也支援 ECMAScript 3。這些瀏覽器與 IE 一起,繼續推動 JavaScript 的成長。

  AJAX 的誕生

  AJAX,即非同步 JavaScript 和 XML,是一種在 ECMAScript 3 年代誕生的技術。雖然它並非標準的一部分,不過微軟為其 IE5 瀏覽器實現了某些對 JavaScript 的擴充套件。其中之一就是 XMLHttpRequest 功能(以 XMLHTTP ActiveX 控制元件的形式)。該功能允許瀏覽器執行對伺服器的非同步 HTTP 請求,從而允許頁面被即時動態更新。雖然術語 AJAX 直到幾年後才被創造出來,但是這種技術早就到處在用了。

術語 AJAX 是由 Adaptive Path 的聯合創始人 Jesse James Garrett 在這篇標誌性部落格中創造出來的。

  XMLHttpRequest 被證明是非常成功的,多年以後被整合到一個單獨的標準中(作為 WHATWG 和 W3C 組織的一部分)。

  由實現者給語言帶來一些有趣的東西,並且在瀏覽器中實現,從而促進特性的發展,依然是 JavaScript 和相關的 Web 標準(比如 HTML 和 CSS)繼續發展的方式。不過,那時不同派系之間溝通極少,導致拖延和分裂。平心而論,有了任何感興趣的派系提出建議的程式,今天的 JavaScript 開發顯得更有組織。

  玩玩 NETSCAPE NAVIGATOR 6 Netscape Navigator 6

  這個版本支援異常,之前版本在試圖訪問 Google 時候遇到的主要缺陷。不可思議的是,即使在今天,試圖在這個版本中訪問 Google,也會一個看得見的工作頁面。相比之下,如果試圖用 Netscape Navigator 訪問 Google,就會被缺乏異常、不完整的渲染以及糟糕的佈局弄的焦頭爛額。Web 正在快速發展,即使在當時。

  玩玩 INTERNET EXPLORER 5 IE5

  IE5 也能渲染當前版本的 Google。不過,眾所周知,在實現某些特性上面,IE 和其它瀏覽器之間有很多分歧。這些分歧禍害了 Web 很多年,也是長期以來 Web 開發者受挫之源,因為他們經常不得不為 IE 使用者實現特例。

  實際上,要在 IE5 和 IE6 中訪問 XMLHttpRequest 物件,必須要藉助於 ActiveX。其它瀏覽器將其實現為原生物件。

var xhr = new ActiveXObject("Microsoft.XMLHTTP");

  毫無疑問,是 IE5 率先將 AJAX 理念變成現實。不過,直到 IE7,微軟才開始遵循標準,並更貼近共識。有些老公司網站依然需要老版本的 IE 才能正確執行。

  ECMAScript 3.1 和 4:鬥爭之年

  不幸的是,隨後幾年JavaScript 發展並不順利。從 ECMAScript 4 的工作一開始,委員會中就開始出現了強烈的分歧。有一群人認為 JavaScript 需要一些特性來成為一種更強大的語言,這樣就可以用於大型應用程式開發。這群人提出了很多特性,這些特性涉及面廣,變化大。另一群人認為大型應用程式開發不是 JavaScript 適合的方向。由於缺乏一致意見,加上新提出的某些特性的複雜性,將 ECMAScript 4 的釋出變得遙遙無期。

  實際上針對 ECMAScript 4 的工作在 1999 年 版本 3 剛出爐的時候,就已經開始了。網景公司內部討論了很多有意義的特性。不過,實現這些特性的興趣已經逐漸減弱,並且 2003 年剛過沒多久,在新版本 ECMAScript 上的工作就停止了。一個臨時報告發布了,有些實現者,比如 Adobe(ActionScript)和微軟(JScript.NET),使用這個報告作為其引擎的基礎。2005 年,在 AJAX 和 XMLHttpRequest 的影響之下,再度激發了新版本 JavaScript 的興趣,TC-39 重啟了工作。幾年過去了,特性集變得越來越大。在 ECMAScript 4 開發的最高峰,有如下這些特性:

  • 介面

  • 名稱空間

  • 可選的型別註解

  • 可選的靜態型別檢查

  • 結構型別

  • 型別定義

  • 多方法(Multimethods)

  • 引數化型別

  • 尾呼叫

  • 迭代器(Iterator)

  • 生成器(Generator)

  • 內省

  • 型別識別的異常處理器

  • 常量繫結

  • 塊作用域

  • 解構

  • 函式表示式

  • 陣列推導式(Array comprehensions)

  ECMAScript 4 草案將這個新版本描述為編寫大型應用程式而設計。如果你已熟悉 ECMAScript 6/2015,就會注意到很多來自 ECMAScript 4 的特性被重新引入了。

雖然 ES3 靈活,並且在形式上很強大,但是在開發大型軟體系統實踐中,它的抽象能力經常是無法勝任的。由於在 Web 上採用 Ajax 程式設計,在應用程式中大量使用 ECMAScript 作為外掛以及指令碼語言,ECMAScript 程式正變得越來越大,越來越複雜。大型程式的開發可以從靜態型別檢查、名稱隱藏、早繫結以及其它優化手段、直接支援物件導向程式設計等技術上大大受益,而這些都是 ES3 中所缺乏的。 - ECMAScript 4 草案

  一則有趣的歷史片段是如下的 Google Docs spreadsheet,這個檔案展示了幾種 JavaScript 引擎的實現狀態,以及涉及其中的派系的討論。

  開發 ECMAScript 4 的委員會由 Adobe、Mozilla、Opera(以非官方身份)和微軟組成。Yahoo 在大部分標準和特性已經決定了後,進入了這個委員會。Doug Crockford,一個有影響力的 JavaScript 開發者,就是 Yahoo 為此送進委員會的那個人。他鼓吹他的擔憂,強烈反對很多 ECMAScript 4 提議的修改。他從微軟的代表那裡獲得了強烈的支援。Crockford 本人說到:

但是結果微軟的委員也有同樣的擔憂 - 他也認為這門語言正變得太大,失去了控制。在我加入委員會之前,他什麼都沒有說,因為他擔心,如果微軟試著阻攔這件事,就會被指責為反競爭行為。根據微軟過去的表現,也許他們有一些不錯的理由對此在意 - 並且很顯然,這些擔憂是有理有據的,因為已經發生過。但是我勸他說,微軟應該做正確的事情,並且以他的聲譽,他決定他應該,也能說服微軟。所以微軟就在 ES4 上改變了立場。 - Douglas Crockford — JavaScript 的現狀和未來

  開始是懷疑,後來就變成強勢反對 JavaScript。微軟拒絕接受 ECMAScript 4 的所有部分,並且準備採取各種必要的行動來阻止標準獲得通過(甚至法律訴訟)。幸運的是,委員會中的人設法阻止了法律鬥爭。不過,缺乏共識有效地阻止了 ECMAScript 4 推進。

微軟的某些人想在這件事情上採取強硬手段,他們想開始建立書面憑據,開始走申訴程式,想做這些額外的法律程式。我可不想有這種事情。我是不同意 ES4,但是僅限於技術層面,並且我想只限於技術層面;我不想讓它變得比以前更麻煩。我只是想搞清楚什麼事情該做,所以我設法溫和一點。但是微軟依然採取了極端立場,說他們拒絕接受 ES4 的任何部分。所以事情就變成了兩極分化,但是我認為兩極分化是因為 ES4 團隊拒絕考慮任何其它觀點的結果。那時委員會沒有達成共識,這是件糟糕的事情,因為標準小組必須要達成共識。一個標準不應該是有爭議的。 - Douglas Crockford — JavaScript 的現狀和未來

  Crockford 想出一個點子來推進,就是重新弄一個標準,這個標準更簡單,減少一些特性集,這樣所有人都可以同意:沒有新語法,只有來自使用該語言的經歷中的實際提升。這個提案後來被稱為 ECMAScript 3.1。

  有一段時間,兩種標準並存,並且設定了兩個非正式的委員會。不過,ECMAScript 4 太複雜,沒辦法在面對衝突的情況完成。ECMAScript 3.1 更簡單,並且儘管在 ECMA 中有鬥爭,它還是完成了。

  ECMAScript 4 的結束出現在 2008 年,Eich 通過一封電子郵件,傳送了一次奧斯陸會議的內容提要,詳細描述了 ECMAScrpt 走向和版本 3.1 和 4 的未來。

  這次會議的結論是:

  1. 與所有各方充分合作,集中精力完成 ES 3.1,到明年初確定兩個執行標準。

  2. 下一步上的合作超出 ES3.1,會包含語法上的擴充套件,但是會在語義和語法創新上比 ES4 更謹慎。

  3. 有些 ES4 提案已經被認為對 Web 不合理,最好不予討論:包、名稱空間和早繫結。這個結論對於 Harmony 來說很關鍵。

  4. ES4 的其它目標和理念正被改寫,以保持在委員會中的一致;包括類的概念是基於已有的 ES3 概念結合提議的 ES3.1 擴充套件。

  總之,ECMAScript 4 花了近 8 年的時間開發,最後卻被廢棄了。這對涉及的所有人來說都是一個沉重的教訓。

  單詞 "Harmony(和諧)" 出現在上面的結論中。這是將來對 JavaScript 擴充套件時專案的標準名稱。Harmony 會是所有人都同意的方案。在 ECMAScript 3.1 釋出後(以版本 5 的形式,下面我們會看到),所有 JavaScript 中要討論的新主意都會出現在ECMAScript Harmony 中。

  ActionScript

  ActionScript 是一個基於 ECMAScript 4 早期草案的程式語言。Adobe 將其實現為 Flash 應用程式套件的一部分,也是它支援的唯一的指令碼語言。這就讓 Adobe 採用強硬的立場來支援 ECMAScript 4,甚至還將他們的引擎(Tamarin)開源釋出了,以希望加快 ECMAScript 4 的採納。Adobe 員工 Mike Chambers 爆光了一個在此事上的有趣看法:

ActionScript 3 沒有消失,我們基於最近的決定,沒有從中刪除任何東西..我們會繼續跟蹤 ECMAScript 規範,但是正如我們一直所做的那樣,我們會創新,儘可能推動 Web 向前發展(正如我們在過去已做過的那樣)- Mike Chamber 的部落格

  ActionScript 開發者期望 ActionScript 中的創新會驅動 ECMAScript 中的特性。不幸的是這事從來沒有出現過,而且後來出現在 ECMAScript 2015 中的特性與 ActionScript 在很多方面不相容。

  有人看到這是微軟嘗試保持控制 ECMAScript 語言和實現的一種策略。此時,唯一可行的 ECMAScript 4 引擎是 Tamarin,所以此時佔有 80% 瀏覽器市場份額的微軟可以繼續使用它自己的引擎(以及擴充套件),而不用承擔切換到競爭對手的替代品的代價或者花時間內部實現一切。 其他人只是說微軟的異議僅僅是技術上的,跟來自 Yahoo 的人一樣。Microsoft 的引擎 JScript 此時與其它實現有很多差異。有人已經看到這是保持祕密控制該語言的一種手段。

  ActionScript 目前依然是 Flash 的開發語言,而 Flash 隨著 HTML5 的到來,逐漸淡出了人們的視野。

  如果 ECMAScript 4 已經被流行 JavaScript 引擎實現的話,ActionScript 依然與它最像:

package {
    import flash.display.Sprite;
    public class MyRectangle_v3 extends Sprite {
        private var _outlineWeight:Number;
        private var _color:uint;
        private var _xLocation:int;
        private var _yLocation:int;
        private var _rectangleWidth:int;
        private var _rectangleHeight:int;

        public function MyRectangle_v3(outlineWeight:Number, color:uint, 
                                       xLocation:int, yLocation:int, 
                                       rectangleWidth:int, rectangleHeight:int) {            
            _outlineWeight = outlineWeight;
            _color = color;
            _xLocation = xLocation;
            _yLocation = yLocation;
            _rectangleWidth = rectangleWidth;
            _rectangleHeight = rectangleHeight;
        }  

        public function draw():void{
            graphics.lineStyle(_outlineWeight);
            graphics.beginFill(_color);
            graphics.drawRect(_xLocation, _yLocation, _rectangleWidth, _rectangleHeight);
            graphics.endFill();
        }  
    }  
}

  E4X?什麼是 E4X?

  E4X 是一個公認的 ECMAScript 擴充套件的名稱。它在 ECMAScript 4 開發期間釋出(2004年),所以就採用了綽號 E4X。其實際名稱是 ECMAScript for XML,並被標準化為 ECMA-357。E4X 擴充了 ECMAScript,以支援對 XML 內容的原生處理和解析。在 E4X 中,XML 被當作是一種原生資料型別。它最初被主流 JavaScript 引擎(比如 SpiderMonkey)採納,不過之後由於很少有人用而被拿掉。在 Firefox 版本 21 中被刪除。

  除了其名稱中有數字 "4" 之外,E4X 與 ECMAScript 4 沒多大關係。

  如下是一個使用 E4X 的示例:

var sales = <sales vendor="John">
    <item type="peas" price="4" quantity="6"/>
    <item type="carrot" price="3" quantity="10"/>
    <item type="chips" price="5" quantity="3"/>
  </sales>;

alert( sales.item.(@type == "carrot").@quantity );
alert( sales.@vendor );
for each( var price in sales..@price ) {
  alert( price );
}
delete sales.item[0];
sales.item += <item type="oranges" price="4"/>;
sales.item.(@type == "oranges").@quantity = 4;

  可以說,其它資料格式(比如 JSON)已經在 JavaScript 社群中獲得了更廣泛的認同,所以 E4X 出現和消失都沒惹啥亂子。

  ECMAScript 5:JavaScript 的重生

  在 ECMAScript 4 的漫長鬥爭之後,從 2008 年開始,社群就在注意力放在 ECMAScript 3.1 上。ECMAScript 4 被廢棄。在 2009 年,ECMAScript 3.1 完成,並且涉及的各方都簽字確認了。而 ECMAScript 4 即使還沒有真正釋出,也已經被公認為是 ECMAScript 的一個特定變種,所以委員會決定將 ECMAScript 3.1 重新命名為 ECMAScript 5,以避免混淆。

  ECMAScript 5 成為了最受支援的 JavaScript 版本之一,也成為了很多轉譯器的編譯目標。ECMAScript 5 被 Firefox 4 (2011)、Chrome 19 (2012)、Safari 6 (2012)、Opera 12.10 (2012) 和 Internet Explorer 10 (2012)完全支援。

  ECMAScript 5 是對 ECMAScript 3 的一種相當謹慎的更新,它包括:

  • Getter/setters

  • 陣列和物件字面量中的尾隨逗號

  • 保留關鍵字可以作為屬性名

  • 新的 Object 方法(createdefinePropertykeyssealfreezegetOwnPropertyNames 等等)

  • 新的 Array 方法(isArrayindexOfeverysomemapfilterreduce 等等)

  • String.prototype.trim 和屬性訪問

  • 新的 Date 方法(toISOStringnowtoJSON

  • 函式 bind

  • JSON

  • 不可變的全域性物件(undefinedNaNInfinity

  • 嚴格模式

  • 其它次要的變更(parseInt 忽略前導零、丟擲的函式有正確的 this 值,等等)

  所有更新都不需要語法上的修改。那時 getter 和 setter 已經被很多瀏覽器非正式地支援。新的 Object 方法通過給程式設計師更多工具來確保強制某些不變性,來改進“大型程式的編寫”(Object.sealObject.freezeObject.createProperty)。嚴格模式通過阻止很多常見的錯誤源,在這一領域也成為一種強大的工具。額外的 Array 方法改進了某些函式式正規化(mapreducefiltereverysome)。另一個大變化是 JSON:一個受 JavaScript 啟發的資料格式,現在通過 JSON.stringifyJSON.parse 原生支援了。其它變化基於實踐經驗在幾個方面作出了小的改進。總而言之,ECMAScript 5 是適度的改進,幫助 JavaScrpt 成為一種對於小指令碼和較大的專案來說都更可用的語言。依然有很多來自 ECMAScript 4 的好點子被廢棄,並且你會看到這些好點子又通過 ECMAScript Harmony 提案迴歸。

  2011 年,ECMAScript 5 以 ECMAScript 5.1 的形式又來了一次迭代。這個版本澄清了標準中一些容易引起歧義之處,但是沒有提供任何新特性。所有的新特性定於在下一個 ECMAScript 的大發布中。

  ECMAScript 6 (2015) 和 7 (2016): 一個通用的語言

  ECMAScript Harmony 提案成為將來對 JavaScript 的改進的中心。ECMAScript 4 的很多想法被永久封存了,但另外一些則又以新的面目被重新啟用。ECMAScript 6,後來被重新命名為 ECMAScript 2015,被指定為帶來大變化。幾乎所有需要在語法上改變的更新都被放到這個版本中。不過,這次委員會達成了一致,ECMAScript 6 最終於 2015 年釋出。很多瀏覽器廠家已經開始著手實現它的特性,但是大的變動需要點時間。直到今天,並非所有瀏覽器都完全覆蓋 ECMAScript 2015(雖然它們已經很接近)。

  ECMAScript 2015 的釋出導致轉譯器的使用大幅度增加,比如 Babel 或 Traceur。甚至在它釋出之前,因為這些轉譯器跟蹤了技術委員會的進展,人們已經體驗了很多 ECMAScript 2015 的好處。

  一些 ECMAScript 4 的大特性在這個版本的 ECMAScript 中被實現。不過,實現的出發點不一樣了。例如,ECMAScript 2015 中的類只不過是在原型之上的語法糖。這種思維模式減輕了新特性的過渡和開發。

  在我們的JavaScript 2015 特性概述一文中,我們對 ECMAScript 2015 的新特性做了一個全面的概述。你也可以看看 ECMAScript 相容性表,瞭解一下在實現方面我們現在的確切位置。

  新特性小結如下:

  • Let(詞法上的)和 const(不可重新繫結的)繫結

  • 箭頭函式(匿名函式的簡寫)以及詞法 this(包含作用域 this)

  • 類(原型之上的語法糖)

  • 物件字面量提升(計算鍵、短方法定義等等)

  • 模板字串

  • Promise

  • Generator、iterable、iterator 和 for..of

  • 函式的預設引數及剩餘運算子

  • 擴充套件語法

  • 解構

  • 模組語法

  • 新集合(Set、Map、WeakSet、WeakMap)

  • 代理和反射

  • Symbol 資料型別

  • 型別化陣列

  • 內建支援子類化

  • 有保證的尾呼叫優化

  • 更簡單的 Unicode 支援

  • 二進位制和八進位制字面量

  類、let、const、promise、generator、iterators、模組,等等。這些特性都是為了把 JavaScript 帶給更多受眾,幫助開發大型應用程式。

  你也許會驚訝,在 ECMAScript 4 失敗之時,還有這麼多特效能闖過標準化過程這一關。從這個層面上,必須得指出,ECMAScript 4 中很多最具侵入性的特性都沒有被重新考慮,比如,名稱空間、可選型別;同時,其它的特性被以可以通過之前的異議的方式重新考慮了,比如,讓類成為原型之上的語法糖。ECMAScript 2015 依然是個苦差事,花了約 6 年完成(並且需要更長時間完全實現)。不過,這樣艱鉅的一個任務能被 ECMAScript 技術委員會完成,也可以看作是個好兆頭。

  2016 年,一個 ECMAScript 的小修訂版釋出了。這個小修訂版是 TC-39 實施的新發布過程的結果。所有新提案必須經過四個階段的過程。每個達到第四個階段的提案有很大機會會被包含在下一個版本的 ECMAScript 中(不過委員會依然可以選擇推遲將其列入議程)。這樣,提案就幾乎可以獨立開發(不過與其它提案的互動必須在考慮之列)。提案不會中斷 ECMAScript 的開發。如果一個提案已經準備列入,並且足夠的提案已經達到第四階段,那麼就可以釋出一個 ECMAScript 新版本。

  2016 年釋出的版本是一個相當小的版本。它包括:

  • 取冪運算子(**

  • Array.prototype.includes

  • 一些小的更正(generator 不能與 new 一起用等等)。

  不過,在 2016 年,某些有趣的提案已經達到第四階段,所以 ECMAScript 的未來是什麼呢?

  未來與超越:ECMAScipt 2017 及以後

  也許目前進行中的最重要的第四階段提案是 async/awaitAsync/await 是對 JavaScript 的一種語法擴充套件,可以讓處理 promise 變得更爽。例如,對於如下 ECMAScript 2015 程式碼:

function apiDoSomethingMoreComplex(withThis) {
    const urlA = '...';
    const urlB = '...';

    httpLib.request(urlA, withThis).then(result => {
        const parsed = parseResult(result);
        return new Promise((resolve, reject) => {
            database.update(updateStatement, parsed).then(() => {
                resolve(parsed);
            }, error => {
                reject(error);
            });
        });
    }).then(result => {
        return httpLib.request(urlB, result);
    }).then(result => {
        return worker.processData(result);
    }).then(result => {
        logger.info(`apiDoSomethingMoreComplex success (${result})`);
    }, error => {
        logger.error(error);
    });
}

  把它與如下的 async/await 程式碼比較:

async function apiDoSomethingMoreComplex(withThis) {
    const urlA = '...';
    const urlB = '...';

    try { 
        let result = await httpLib.request(urlA, withThis);
        const parsed = parseResult(result);
        await database.update(updateStatement, parsed);
        result = await httpLib.request(urlB, parsed);
        result = await worker.processData(result);
        logger.info(`apiDoSomethingMoreComplex success (${result})`);
    } catch(e) {
        logger.error(e);
    }
}

  其它第四階段的提案在範圍上都是次要的:

  • Object.valuesObject.entries

  • 字串補白

  • Object.getOwnPropertyDescriptors

  • 函式引數允許尾隨逗號

  這些提案都是定於在 2017 年釋出,不過委員會可能會選擇自行決定推遲。不過,僅是有async/await 這一點就是一件讓人激動的變動。

  但是未來並非止步於此!我們可以看看其它的一些提案,瞭解一下更遠的未來會出現什麼。一些有趣的提案是:

  • SIMD API

  • 非同步迭代(async/await + 迭代)

  • Generator 箭頭函式

  • 64 位 整型操作

  • Realm(狀態分離/隔離)

  • 共享記憶體和原子

  JavaScript 正越來越像一門通用的語言。不過,還有一件對 JavaScript 的未來會產生重大影響的大事情。

  WebAssembly

  如果你還沒聽說過 WebAssembly,就應該讀讀這篇文章。自 ECMAScript 5 釋出以來,引發的庫、框架和一般開發的激增,已經讓 JavaScript 變成了對其它語言的一個有興趣的目標。對於大的程式碼庫,可互操作性是關鍵。比如說遊戲。遊戲開發的通用語言依然是 C++,並且它對很多架構來說都是可移植的。將一個 Windows 遊戲或者電子遊戲移植到瀏覽器上被看作是一件不可能實現的任務。不過,當前 JIT JavaScript 虛擬機器不可思議的效能讓這成為可能。於是,像 Emscripten 這種 LLVM-to-JavaScript 編譯器應運而生。

  Mozilla 看到了這點,並開始著手研究讓 JavaScript 變成編譯器的合適目標。Asm.js 誕生了。Asm.js 是 JavaScript 的一個嚴格子集,用來作為編譯器的目標。JavaScript 虛擬機器可以被優化為識別這個子集,並且生成比目前可能在普通 JavaScript 程式碼中更好的程式碼。瀏覽器慢慢變成了一個編譯應用的全新目標,而 JavaScript 在其中心。

  不過,有些限制是 Asm.js 也不能解決了。畢竟這與 JavaScript 的用途無關,所以必須要對 JavaScript 作出改變。要讓 web 成為其它語言的合適目標,就需要點不同的東西,而這正是 WebAssembly 所有的。WebAssembly 是用於 Web 的位元組碼。任何帶有合適編譯器的程式,都可以被編譯為 WebAssembly,然後執行在合適的虛擬機器上(JavaScript 虛擬機器可以提供所需的語義)。實際上,首版 WebAssembly 就以與 Asm.js 規範一對一相容為目標。WebAssembly 不僅帶來了載入時間更快的承諾(解析位元組碼比解析文字更快),還帶來了 Asm.js 中目前還不能用的可能優化。想像一下,JavaScript 和你已有的程式碼之間能完美互用的 Web。

  乍一看,這好像是危及到 JavaScript 的發展,然而事實恰好相反。通過讓其它語言和框架更容易與 JavaScript 互用,JavaScript 就可以繼續發展為一門通用的語言。而WebAssembly 是為此必需的工具。

  目前,Chrome、Firefox 和 Microsot Edge 的開發版支援 WebAsembly 規範草案,並且能夠執行演示應用程式

 總結

  JavaScript 的歷史漫長而崎嶇。它先被提議為用於 Web 的 Scheme,然後早早就被類 Java 的語法束縛住了。它的第一個原型在幾周之內就被開發出來了。受市場之害,它在兩年之內變了三個名字。然後被標準化了,同時得到一個聽起來像皮膚病的名字。在三次成功的釋出後,第四版陷入開發地獄約八年。開發方向一變再變,莫衷一是。然後,純通過一個特性(AJAX)的成功,社群又重歸行動一致,恢復了開發。第 4 版被廢棄,一個次要版本,即人人皆知的 第 3.1 版本,被重新命名為 第 5 版。第 6 版又在開發上花了很多年,不過這次委員會成功了,雖然又決定改名,但是這次是改為 2015。這個修訂版很大,花了很多時間實現,但是最終,給 JavaScript 帶來了新風。社群像以前一樣活躍。Node.js、V8 和其它專案已經把 JavaScript 帶到了一個前所未有的地步。Asm.js、WebAssembly 正進一步改進它。並且不同階段活躍的提案都讓 JavaScript 的未來像以前一樣光明。這是一條漫長的路,充滿崎嶇,而 JavaScript 依然始終是最成功的語言之一。這本身就是一種證明。永遠把賭注押在 JavaScript 上。

相關文章