12. ECMAScript 3 の定義

TC39 の初回会合では JavaScript 1.0 および JavaScript 1.1 に対する様々な言語拡張が提案され、一部は言語仕様の第 1 ドラフトに取り込まれた。しかし TC39 の技術的ワーキンググループは基礎的な言語の仕様が完成するまで新しい機能を一切考慮しないことで合意した。第 1 版の作成のほぼ全体を通じて、追加の可能性がある言語拡張は仕様ドラフトの補遺に追いやられた [TC39 1997a, Appendix B]。

1997 年 7 月の TC39 会合 [TC39 1997g] までの間に仕様の第 1 版は完成に近づいていたので、この会合では仕様の次の版で取り入れるべき新機能が主に議論された。Netscape は JavaScript 1.2 の機能を実装する SpiderMonkey エンジンを搭載した Netscape 4.0 を出荷することで既に方向を示していた。Scott Wiltamuth は Microsoft が作成した「ECMAScript 2.0」の初期提案 [Microsoft 1997] を示した。この提案には switch 文、do-while 文、ラベル付き文、ラベルへの break/continue=== 演算子、!== 演算子、そして引数オブジェクトの caller プロパティが含まれる。それとは別に、Microsoft の Andrew Clinick は条件付きコンパイルのサポートの追加を提案した [Clinick 1997]。「バージョン 2」のスタート地点は 10 月に Microsoft が Internet Explorer 4.0 のコンポーネントとして JScript 3.0 を出荷したときに固まった。 1997 年末の時点で Netscape [1997c] と Microsoft [2009b] のブラウザが実装していた ECMAScript 第 1 版に対する主な言語拡張を図 17 に示す。

機能 JavaScript
1.2
JScript
3.0
ECMA-262
第 3 版
do
ラベルへの break/continue
switch
入れ子になった関数
関数式
オブジェクトリテラル
配列リテラル
===!==
正規表現リテラル
delete 演算子
全てのオブジェクトに対する __proto__ 疑似プロパティ
配列メソッド: concat, slice
配列メソッド: push, pop, shift, splice, unshift
継承された要素を持つ疎配列
文字列メソッド: 正規表現を使った fromCharCode,
match, replace, search, substr, split
文字列メソッド: charCodeAt
正規表現メソッド: compile, exec, test
正規表現プロパティ: $1, ..., $9, input
正規表現グローバルプロパティ lastMatch, lastParen
leftContext, rightContext
引数オブジェクトがローカルな宣言をプロパティに持つ
arguments.callee
arguments.caller
watch/unwatch 関数
import/export 文と署名付きスクリプト
条件付きコンパイル
debugger キーワード
図 17. 1997 年の主要なウェブブラウザで出荷されていた ECMA-262 第 1 版に対する言語拡張。多くは ECMA-262 第 3 版に取り込まれた。

この頃までに公式の TC39 会合はメンバー企業を代表するグループやプログラムマネージャが標準化の管理と戦略について話し合う場となっており、TC39 の技術的な作業の多くは非公式の技術的ワーキンググループで行われるようになっていた。7 月の TC39 会合ではバージョン 2 作成までに踏むステップについて合意があった。また作業項目、機能提案、受け入れ基準を示す権限を技術的ワーキンググループに与えることにも TC39 は合意した。バージョン 2 ではドラフトを成熟させるため、そして外部からのフィードバックを受けるために、第 1 版より長い時間が割り当てられることになった。第 1 ドラフトの目標とされたのは 1997 年 12 月である。9 月の会合 [TC39 1997h] ではさらに、バージョン 2 は仕様第 1 版に準拠するプログラムとの後方互換性を保たなければならないことに合意があった。

こういった判断が下されたとき ISO のファストトラックプロセスは始まっておらず、ISO 版の仕様と合わせるために ECMA-262 に新しい版が必要になるとは予想されていなかった。そのため 1998 年の初めには、メンバーの重複する二つのワーキンググループがそれぞれ個別の仕様ドラフトに取り組む状況になった。しばらくして「第 2 版」と「バージョン 2」が同じにならないことが明白になったにもかかわらず TC39 のメンバーは次に発表される仕様を指して「バージョン 2」あるいは「V2」 という名称を使い続け、それが「第 3 版」として公開される可能性が高いと分かったときでも名称を改めなかった。TC39 内で使われるバージョン名が最終的に公開される仕様での名前と異なるのはこれが最後ではない。

1997 年の末、技術的ワーキンググループの参加者が大きく変化した。1998 年を通じてワーキンググループ会合に二回以上出席したと会合の報告書に記録されている人物の名前を図 18 に示す。第 1 版の作成に関わったワーキンググループの定期的な参加者と比べると、続けて参加しているのは Clayton Lewis だけである。Brendan Eich は 1988 年 2 月の会合に一度参加しただけで、以降は Netscape ブラウザのコードをオープンソースにする活動を行う Mozilla プロジェクトの共同設立者となった [Mozilla Orgnanization 1998]。TC39 における Netscape の主任言語設計者の役割は Waldemar Horwat が受け継いだ。同様に Microsoft の Shon Katzenberger はサバティカルを取ってその後は他のプロジェクトに移動し、TC39 における Microsoft の責任者は Herman Venter と Rok Yu が務めた。

  • Norris (Boyd)
  • Drew (Lytle)
  • ndrew (Clinick)
  • Karl (Matzke)
  • Mike (Cowlishaw)
  • Mike (McCabe)
  • Jeff (Dyer)
  • Dave (Ragget)
  • Bill (Gibbons)
  • Herman (Venter)
  • Waldemar (Horwat)
  • Rok (Yu)
  • Mike (Ksar)
  • Chris (Weight)
  • Clayton (Lewis)
図 18. 1998 年における TC39 技術的ワーキンググループの定期的な参加者

1997 年の 10 月、技術的ワーキンググループはバージョン 2 で追加する機能の候補からなるリストを作成した (補遺 H)。このリストで「合意があった」とされている機能はいくつかの例外を除けば Netscape の JavaScript 1.2 および Microsoft の JScript 3.0 が持つ機能の和集合である。合意があった機能の一つ toSource 関数は、Brendan Eich が JavaScript 1.3 用に開発したオブジェクトのシリアライズ (永続化) スキームに対応する1。仕様に含めるコンセンサスが取れなかった議論の余地の残る機能は別のリストとされている。第 1 版のときと同様に、ワーキンググループが集中したのは既に実装された機能を正確に記述すること、そして実装間の食い違いを一つ残らず解決することだった。しかし「合意があった」機能のリストには例外処理機構や instanceof 演算子といったどの実装にも含まれない機能が含まれ、こういった機能には第 1 版では必要なかった設計の仕事が必要となった。最終的に ES3 に加わった機能の中で 1998 年以前のブラウザに存在しないものを図 19 に示す。

  • try-catch-finally と例外オブジェクト
  • instanceof 演算子と in 演算子
  • オブジェクトのプロトタイプメソッド: hasInstance, hasOwnProperty, isPrototypeOf, propertyIsEnumerable
  • undefined に対するグローバル束縛
  • toFixed, toExponential, toPrecision
  • URI を扱う関数
  • Unicode 文字が含まれる識別子
  • 基礎的な I18N メソッド: オブジェクトの toLocaleString; 配列の toLocaleString; 数値の toLocaleString; 文字列の localeCompare, toLocaleLowerCase, toLocaleUpperCase; 日時の toLocaleDateString, toLocaleTimeString
図 19. ES3 の新機能であって 1998 年以前のブラウザに存在しないもの。TC39 が ES3 を作成している間にブラウザに追加された機能もある。

技術的ワーキンググループは月に一回のペースで対面会合を行うリズムを確立した。プロジェクト編集者の Mike Cowlishaw [Cowlishaw 1999b; Appendix I] は仕様の各節の現在状況を追跡する文書を管理した。各節の状況は「V1 から変更無し」「準備できていない」「議論が必要」「機能は受理された」「内容は合意された」のいずれかとされた。「機能は受理された」は仕様で定義する機能について TC39 で合意があったことを表し、「内容は合意された」は実際の仕様に含まれる文章がレビューされ受理されたことを表した。

新しい仕様の作業ドラフトの編集者は Bill Gibbons だった。毎回の会合では提案や未解決の問題に関するプレゼンテーションや議論の予定表が用意された。提案はアルゴリズムとして書かれた新しい (あるいは改訂された) 仕様文書として示されることが多かった。会合では参加者が前回の会合以降に見つけた問題を議論する一般的な状況レビューもあった。提案や問題の解決に合意があると、Gibbons はそれを作業ドラフトに取り入れていった。V2 の最初の完成したドラフト [Cowlishaw et al. 1998] は 1998 年 4 月に公開された。この文書は ECMA-262 第 1 版に基づいており、並行して作成中だった ECMA-262 第 2 版 (ISO 版) における変更は含まれていない。またタイトルページには、この文書には Netscape と Microsoft が提出した変更の提案が含まれるとある。ISO 版の作成が 9 月に完了した後、Gibbons は ES2 で行われた変更を当時の V2 作業ドラフトに統合した。

当時 Unicode はまだ新しい技術であり、言語実装者たちは Unicode をプログラミング言語に統合する様々なアプローチを探っている状態だった。特に問題だったのが、Unicode に正規化形式が複数存在するために振る舞いが同じ文字の列に異なるエンコーディングがあり得るという事実である。Hewlett-Packard の Tom McFarland は 1998 年 5 月の会合に主席した後、ECMAScript への Unicode の統合と国際化 (I18N) に関して彼が問題だと感じた部分を指摘するメモ [McFarland 1998] を提出した。1998 年 11 月、数回の会合での議論に続く形で、TC39 は IBM の Richard Gillam を議長とする「I18N ワーキンググループ」を設立した [Gillam 1998]。I18N グループは言語の中心部に少数の基本的な I18N 機能を追加することに議論を集中させ、国際化と地域化のより複雑な側面は省略可能なライブラリで個別に定義するようにして議論を遅らせることを素早く決断した [Gillam et al. 1998]。しかし、ここで構想されたライブラリの仕様が完成したのは 2012 年だった [Lindenberg 2012]。言語の中心部に少数のロケール特有な関数を加えるのに加えて、I18N グループは非ラテン文字を識別子に取り入れる方法についても議論を終結させた。具体的には、実装に与えられるソースコードが Unicode 正規化形式 C で表されるという仮定の下で ECMAScript 言語仕様を書くことを推奨して正規化の問題の大部分を回避した。また Unicode 正規化に関するサポートを言語の中心部には含めず、正規化のプログラム的なサポートは省略可能なライブラリで行うことも選択された。

V2 に向けた重要なタスクの一つが JavaScript の例外処理機構の設計だった。1998 年 2 月 [TC39 1998c]、Microsoft の Herman Venter と Netscape の Waldemar Horwat がそれぞれ設計のスケッチを提示した。いずれも Java の try-catch-finally 文の構文を大まかに真似ていたものの、Java およびもう一方の設計とは構文的にも意味論的にも大きく異なっていた。

Microsoft の設計 [Venter 1998b] では、任意の値を例外として送出できる。try 文は単一の catch 節を持ち、catch 節は捕捉された例外値に初期化されるローカル変数を宣言する。try ブロックから伝播される任意の例外は無条件に捕捉され、finally は存在しない。

Netscape の設計 [Horwat 1998] でも、任意の値を例外として送出できる。しかしこの設計では一つの try 文が複数の catch 節を持つことができ、instanceof による構文的な判別によって実行する節が決定される2。例外にマッチする catch が存在しないと、finally 節の実行が起こってから例外はスタックを上に登る。instanceof を使った判別は後に if を使った判別3に変更された。if を使った判別では式を真偽値に評価し、その値で対応する catch 節が選択されるかどうかを決定する。

1998 年 2 月の会合で、TC39 は trycatch のキーワードを使うこと、そして throw 文を通して任意の値 (組み込みの例外クラスのインスタンスである値に限らない全ての値) が例外を表現できるようにすることに合意した。1998 年 3 月のワーキンググループ会合 [TC39 1998d] では Waldemar Horwat が finally 節を含めるべきとの意見を述べ、実装の詳細についてさらに調査することに合意があった。4 月の作業ドラフト [Cowlishaw et al. 1998] には Netscape の設計が取り入れられているものの、finally のサポート、catch が作成する変数束縛のスコープ、複数の catch 節が許されるかどうか、instanceofcatch のセレクタとして使うべきかどうか、選択されなかった例外を自動的に再送出するべきかどうかについてはどれも未解決のままだった。図 20 に Microsoft の提案、Netscape の改訂後の提案、そして最終的に ES3 が規定した設計を示す。Netscape の設計では個別のセレクタ式を使って catch 節を選択できるのに対して、Microsoft の設計および ES3 の最終的な設計では単一の catch ブロックの中にユーザーが書いたロジックを使って異なる例外が区別される。

Microsoft の設計
try {
  doSomething();
} catch (var e) {
  if (e == "thing")
    console.log("thing")
  else if (e == 42)
    console.log("42")
  else {
    console.log(e);
    cleanup();
    throw e; // 再送出
  }
}
// 構文的な finally はない
cleanup();
Netscape の設計
try {
  doSomething();
} catch (e if e =="thing") {
  console.log("thing")
} catch (e2 if e2 == 42) {
  console.log("42")
} catch (e3) {
  console.log(e3);
  throw e3; // 再送出
} finally {
  cleanup();
}
最終的な ES3 の設計
try {
  doSomething();
} catch (e) {
  if (e == "thing")
    console.log("thing")
  else if (e == 42)
    console.log("42")
  else {
    console.log(e);
    throw e; // 再送出
  }
} finally {
  cleanup();
}
図 20. 考案された例外処理の設計。この例で doSomething は二種類の例外を送出する可能性があり、現在の関数はそれぞれの例外に対して異なる対応を行ってから実行を続ける必要がある。この二つ以外の任意の例外は「再送出」され、現在の関数を呼び出した関数に伝播される。現在の関数は doSomething が例外を送出したかどうかに関わらず cleanup を実行する必要がある。

ECMAScript が複数の match 節をサポートすべきかどうかという問題は 1999 年 9 月の規格ドラフトの最終技術レビュー [TC39 1999b] まで解決されないままとなり、結局この機能は将来に再考するとして採用は見送られた。また、組み込みの例外クラスの集合を規格が定義することに関して合意に達したのもようやく最終レビューでのことだった。

catch 節のガード式は、Java などの静的型付けでクラスベースの言語が持つ機能を動的型付けとプロトタイプ継承を特徴とする JavaScript で採用するときに TC39 が直面した困難の例と言える。Java では送出された例外を処理する catch 節の選択は部分型の包含判定を通して行われる。この判定は静的に宣言されたクラス階層だけを使うので副作用を持たず、実際にコールスタックを巻き戻す前に行うことができる。しかし JavaScript にはクラスや静的なクラス階層といった概念が公式には存在しないので、TC39 は任意の値を例外として送出できるようにした。JavaScript で catch 節の選択を行うにはガード式で任意の式を評価できる必要があり、もちろんガード式には代入や関数呼び出しが含まれる可能性がある。しかし式の評価には適切な字句的および動的な環境の作成が必要であり、あるガード式の評価が以降のガード式の評価に影響する副作用を持つこともある。とある中間提案で Waldemar Horwat [Horwat 1998] は、catch 節のガード式を評価するタイミングおよび順序を実装が決められるようにするための散文からなる複雑な仕様を提出した。その提案では一つのガード式を複数回評価することさえ許されていた。Horwat はデバッガがスタックを巻き戻す前に例外が未処理になるかどうかを判定できることを望んでいた。この設計が受理されなかったのは幸運だった。以降の経験からは、実装の間にこういった振る舞いの差異があると、複数のブラウザで動作しなければならないウェブページで相互運用性の問題が大量に生まれることが判明している。

Java の概念や構文を JavaScript 向けに変換するとき困難に直面したもう一つの例として intanceof 演算子がある。Java の instanceof 演算子は二項演算子であり、左オペランドが右オペランドの名前をしたクラス型のインスタンスあるいは右オペランドの名前をしたクラス型の部分型のインスタンスであるかどうかを判定する。Herman Venter [Venter 1998a] による instanceof の初期提案は Java の構文をそのまま採用し、右オペランドが識別子であることを要求した。しかし JavaScript にはクラスという概念がそもそも存在せず、新しいオブジェクトを作成する方法はいくつもある。Venter の提案では instanceof の判定でコンストラクタ関数によるパターンを使うことが仮定されており、右オペランドは動的にコンストラクタオブジェクトに評価されるオブジェクト、つまりファーストクラスの関数値とされた。このとき右オペランドは型の参照ではなくファーストクラスの値なので、しばらくして提案は右オペランドに式を与えられるように変更された。instanceof の実行時意味論は左オペランドのプロトタイプ継承チェーンを走査して、右オペランドの prototype プロパティの現在値に一致するオブジェクトがあるかどうかを調べるものとして定義される。多くの簡単なコンストラクタに対しては、こう定義すると new 演算子をコンストラクタに適用して作成されたオブジェクトに対してマッチが発生する。

Java の経験があるプログラマが JavaScript を学ぶと、instanceof はオブジェクトの種類を判別する信頼できる手段だと考えることが多い。しかし経験を積んだ JavaScript プログラマは instanceof の利用を避ける。コンストラクタが返したオブジェクトが動的な instanceof の判定をパスするとは限らず、さらにオブジェクトのメタ構造は改変可能なため instanceof を反復して使ったとき冪等性が成り立つとも限らない。また判定されるオブジェクトがコンストラクタと異なる HTML フレームで作成されているときも正しい判定が行われない。最後に、たとえ結果が true になったとしても、判定したオブジェクトがコンストラクタによって作成されるデータおよび振る舞いのプロパティを持たない可能性がある。

ES3 には内部関数の宣言と関数式が含まれる。これらは JavaScript 1.2 で最初に導入された機能と同様である。ただし {} ブロックに含まれる文および部分文としてのネストされた関数宣言は明示的に禁止された。後に Waldemar Horwat [Horwat 2008b] はこの理由を説明した:

  1. そういった関数はまだ存在していない変数が含まれるスコープをキャプチャできるので、その宣言を (var と同様に) トップレベルに巻き上げるのは上手く行かない。ES3 にローカルスコープは存在しなかったものの、例外スコープは存在するので同じ問題が起こる。この問題は定数や動的な (実行時) 型注釈を言語に追加すると悪化する ── そういった関数は未作成の定数をキャプチャでき、さらに悪いことに、型が計算されていない変数さえもキャプチャできる!
  2. そういった宣言に実行の流れが達するタイミングで宣言を束縛することは可能だが、このローカル束縛の仕組みを関数のサポートのためだけに ES3 に追加したくなかった。
  3. そういった宣言が if 文の部分文である場合、プログラマの意図は if 文の条件式が true のとき (else 節では false のとき) だけ宣言を作成し、それを囲む最も近いブロックスコープに宣言を置くという処理である。これは条件付きコンパイルの一種と言える。属性を持ったブロックは内部の定義にその属性を与える非スコープのブロックなので、一つの if 文に複数の定義を付けることもできる。

主要なブラウザはこの注意事項を気にかけず、ブロック内における関数宣言を実装した。しかし各実装はブロック内における関数宣言に独自の意味論を持たせたので、15 年後に ES6 の設計者は大きな問題を抱えることになった [TC39 2013b, Function In Block Options; §21.3.2]。

1998 年の春には第 3 版の完成が 6 月の Ecma 総会に間に合わないことが明白になった。ただ 12 月の Ecma 総会での承認は可能に思えた。3 月、ワーキンググループは 12 月の目標に間に合わせるために削除あるいは延期する機能を選定するトリアージを行った [Clinick 1999]。__proto__ プロパティ、シャープ変数、スタック具象化用の呼び出しオブジェクト、そして明示的なクロージャオブジェクトは恒久的に削除された。将来の版で追加される可能性を残して延期された機能には、アトミック操作、例外の catch におけるガード、条件付きコンパイル、日付スカラー、十進算術、汎用シーケンス演算子、省略可能な I18N ライブラリ、外部呼び出しインターフェース、toSource を使った永続化、数値単位の構文および算術のサポート、そしてリテラルを定義するための拡張可能な構文がある。

ワーキンググループは 1999 年 5 月から 9 月の間に四回の会合を開催し、仕様第 3 版の最終ドラフトを完成させるために問題を解決していった。この時期に解決しなければならなかった重要な設計上の問題には、正規表現を使ったマッチングの意味論を記述するアルゴリズム的な仕様の作成、組み込みで提供する例外型の選定、関数式の束縛に関する意味論の決定、そして Unicode サポートを言語に取り入れる上での詳細の明確化がある。

1998 年 8 月に Mike Cowlishaw [1999c] が配布した「E3 ドラフト進捗状況」では、全ての節の進捗状況が「内容は合意された」あるいは「V1 から変更無し」になった。8 月 25 日、Bill Gibbons ら [1999] は「第 3 版最終ドラフト」を配布し、新しい仕事へ移るために TC39 を離れた。残された変更をドラフトに取り込む責任者は Herman Venter と Waldemar Horwat が務めた。

最後の ES3 作成会合 [TC39 1999b] では Horwat が編集上および技術上の小さな問題の修正を記した長いリストを準備した。ただ通常の JavaScript プログラマに影響のある変更は少ない。例えば組み込みの例外 ConversionErrorRegExpError は削除され、それぞれ TypeErrorSyntaxError に置き換えられた。

8 月のドラフトでは FunctionExpression4 (関数式) に関数名として与えることができる省略可能な識別子の意味が何も規定されていなかった。これは例えば次のようなコードで問題になる:

function fact(n) {throw "wrong fact"}; // 関数宣言
var lambdaFact = function fact(n) {    // 関数式: これは fact を束縛するのか?
  return n<=1 ? 1: fact(n-1);
};
lambdaFact(5); // これは再帰呼び出し? 例外の送出?
ES3 ドラフト

8 月のドラフトでは FunctionExpression の先頭にある factfact に対する字句的束縛を作らないとされたので、lambdaFact を呼び出すと例外が送出される。9 月の会合でこの仕様の改訂が合意され、 FunctionExpression の名前は関数式の本体内でのみ有効な自身に対するローカルな束縛を作成するとされた。

土壇場で追加された最も驚くべき機能は Waldemar Horwat が会合で提案した「関数の融合 (joined function)」である。関数の融合があると、実装は次のような状況で同じ関数を何度も返せるようになる:

function getClosure() {return function() {/* 自由変数を参照しない */}}
var firstTime = getClosure();
var secondTime = getClosure();
// 次の行が true を表示するか false を表示するかは実装依存である
console.log(firstTime === secondTime); // 同じオブジェクトか?
ES3 のみ

Waldemar Horwat はクロージャ作成のオーバーヘッドを気にしており、この変更があれば一部のよくある状況でクロージャを再利用する決定権を実装に与えられると論じた。Herman Venter が多少の懸念を表明したものの、最終的に TC39 はこの変更に合意した。これは重大な設計ミスとなった可能性もあった。なぜなら以降のウェブブラウザの経験からは、関数の融合によって生じる上述したような観測可能な実装の差異があると、ウェブサイトが全てのブラウザで正しい動作を行えなくなる場合があることが分かったからである。幸いどのブラウザも関数の融合を実装せず、この機能は 2009 年に ES5 仕様から削除された。

八進リテラル (先頭に 0 が付いた数値リテラル) と文字リテラル内での八進エスケープシーケンスは非推奨となり、規格内で規定的な仕様の部分から非規定的な Annex B5に移された。同様に Y2K に準拠しない Date メソッド、文字列に対する escape 関数と unescape 関数、そして文字列の substr メソッドも Annex B に移動した。これらは廃止とみなされたものの、当時のウェブサイトでは利用されていた機能である。そういった機能を規格の中で非規定的な Annex B に移すことで、それらが使うべきではない非推奨な機能となった事実が周知され、最終的に実装が該当の機能を削除しやすくなることが期待された。しかしこれは甘い考えだった。ブラウザ実装者は規格であるかどうかに関わらずウェブで一度でも使われたことがある機能の削除を非常に嫌うことを TC39 メンバーはまだ完全に理解していなかった ── ウェブページが消えることはない。

未解決の問題に対するレビューと解決が終わった後、TC39 は会合で決まった変更を取り入れることを条件に仕様を完全なものとして反対意見無しに受理した。Waldemar Horwat と Herman Venter が最終文書 [TC39 1999e] を作成し、1999 年 10 月に Ecma 事務局に受け渡した。最終ドラフトには、文書の執筆、技術的会合への出席、あるいはメールでの議論を通して ECMA-262 の最初の三版へ貢献した人物全員のリストが含まれている (図 21)。

Mike Ang Gary Fisher Clayton Lewis Sam Ruby
Christine Begle Richard Gabriel Drew Lytle Dario Russi
Norris Boyd Michael Gardner Bob Mathis David Singer
Carl Cargill Bill Gibbons Karl Matzke Randy Solton
Andrew Clinick Richard Gillam Mike McCabe Guy Steele
Donna Converse Waldemar Horwat Tom McFarland Michael Turyn
Mike Cowlishaw Shon Katzenberg Anh Nguyen Herman Venter
Chris Dollin Cedric Krumbein Brent Noorda George Wilingmyre
Jeff Dyer Mike Ksar Andy Palay Scott Wiltamuth
Brendan Eich Roger Lawrence Dave Raggett Rok Yu
Chris Espinosa Steve Leach Gary Robinson
図 21. ECMA-262 の第 1 版、第 2 版、第 3 版の技術的貢献者

11 月、最終ドラフトに含まれる編集上および技術上の小さな誤りがいくつか見つかり、修正された [TC39 1999a]。最も重要だったのが Microsoft による発見で、正規表現を使った String.replace の JScript における実装を最終ドラフトに沿ったものに変更すると、microsoft.com を含む多くのウェブサイトが正しく動作しないことが判明した。これを受けて TC39 は Microsoft の以前の実装に合うよう仕様を変更することに合意した。

1999 年 12 月 16 日、Ecma 総会 [Ecma International 1999] は ECMA-262 第 3 版 [Cowlishaw 1999a] を仕様として承認した。Waldemar Horwat [2003b] は 2000 年 3 月から ES3 の非公式な正誤表を管理した。主要なブラウザの ES3 準拠バージョンは 2000 年の間に出荷され、Microsoft は 2000 年 7 月に IE5.5 の一部として JScript 5.5 を、Netscape は 2000 年 11 月に Netscape 6 の一部として JavaScript 1.5 をそれぞれ出荷した。ECMA-262 第 3 版を次の版が置き換えるのは 2009 年 12 月である。このころブラウザは自動的に更新されず、多くのユーザーがブラウザを更新するのは新しいコンピューターあるいは OS を手に入れたときだけだったので、ES3 の機能をサポートするブラウザを全てのユーザーが使っているとウェブ開発者が仮定できるようになるまでには 10 年近くの時間を必要とした。


  1. toSource のシリアライズスキームには、個別のオブジェクトを JavaScript のソースコードとしてシリアライズするための拡張可能な toSource メソッドの集合、そして環状参照を表すための「シャープ変数 (sharp variable)」が含まれていた。例えばグローバル関数の uneval はルートオブジェクトから始まるオブジェクトグラフをシリアライズし、結果のソースコードは eval でデシリアライズできる。Berndan Eich は #n=#n# といったシャープを付けた変数の構文を Common Lisp から借用した [Steele 1990, 578–579 ページ]。 ↩︎

  2. Mike Shaver は 2019 年の個人的な会話で、複数の catch 節を用意するアイデアは彼が思い付いたものだと語った。その後 Netscape の JavaScript 1.5 [2000] は ES3 に対する非標準言語拡張として複数の catch 節に対応した。 ↩︎

  3. いくつかの作業文書 [Horwat 1998; Venter 1998c] では、catch 節のガード式の前に if キーワードではなくコロンが付いていた。 ↩︎

  4. 関数式は ECMAScript の文法において非終端記号である。慣習により、そういった記号は斜体で書かれる。 ↩︎

  5. Annex B は ES3 仕様の補遺で、廃止された ECMAScript 機能の定義を提供する。 ↩︎

関連書籍 (Amazon アソシエイト)
プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで
JavaScript Primer 迷わないための入門書
JavaScript 第7版
「ものづくり」の科学史 世界を変えた《標準革命》