Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ecmascirpt): ECMAScriptについて #367

Merged
merged 20 commits into from
Feb 21, 2018
3 changes: 3 additions & 0 deletions prh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ rules:
- expected: 子クラス
patterns:
- 小クラス
- expected: されています
patterns:
- されいます

# 文体
- expected: どのように
Expand Down
2 changes: 1 addition & 1 deletion source/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
- Symbol
- Proxy/Reflect API
- [非推奨の機能](./basic/bad-parts/README.md)
- ECMAScript策定プロセス
- [ECMAScript](./basic/ecmascript/README.md)
- [第2部: 応用編(ユースケース)](./use-case/README.md)
- モジュール
- [Ajaxで通信](./use-case/ajaxapp/README.md)
Expand Down
21 changes: 14 additions & 7 deletions source/_layouts/website/page.html
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
{% extends template.self %}
{% block head %}
{{ super() }}
<meta name="google-site-verification" content="bMotEbgYwkzA3k4PkuyK_NUdz0bKh-Phz0oUwNmRSVo"/>
{% extends template.self %} {% block head %} {{ super() }}
<meta name="google-site-verification" content="bMotEbgYwkzA3k4PkuyK_NUdz0bKh-Phz0oUwNmRSVo" />
<style>
/* DocSearch
https://blog.uilicious.com/gitbook-made-better-with-algolia-docsearch-ff1b909ddb0b */
.book {
overflow: hidden;
}

.book-summary {
overflow-y: inherit;
}

nav[role="navigation"], .summary {
nav[role="navigation"],
.summary {
height: 100%;
}
.summary{

.summary {
overflow-y: auto;
}

/* deny access chapter */
.summary li.chapter > span {

.summary li.chapter>span {
cursor: not-allowed;
opacity: .3;
}

/* console ui */


.mirror-console-attach-button-wrapper {
margin-top: -1.275em;
margin-bottom: 1.275em
Expand Down
2 changes: 1 addition & 1 deletion source/basic/class/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ console.log(child instanceof Parent); // => true
console.log(child instanceof Child); // => true
```

<!-- Note:
<!-- Note: instanceof演算子とは`[[Prototype]]`プロパティ

- `instanceof`演算子は`[[Prototype]]`プロパティを見ている
- <https://tc39.github.io/ecma262/#sec-ordinaryhasinstance>
Expand Down
193 changes: 193 additions & 0 deletions source/basic/ecmascript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
---
author: azu
---

# ECMAScript

ここまでJavaScriptの基本文法について見ていきましたが、その文法を定めるECMAScriptという仕様自体がどのように変化していくのかを見ていきましょう。

ECMAScriptは[Ecma International][]という団体によって標準化されている仕様です。
Ecma InternationalはECMAScript以外にもC#やDartなどの標準化作業を行っています。
Ecma International中のTechnical Committee 39(TC39)という技術委員会が中心となって、ECMAScript仕様についてを議論しています。
この技術委員会はMicroSoft、Mozilla、Google、AppleといったブラウザベンダーやECMAScriptに関心のある企業などによって構成されます。

## ECMAScriptのバージョンの歴史

ここで、簡単にECMAScriptのバージョンの歴史を振り返ってみましょう。

| バージョン | リリース時期 |
| -------- | -------- |
| 1 | 1997年6月 |
| 2 | 1998年6月 |
| 3 | 1999年12月 |
| 4 | 破棄[^ES4] |
| 5 | 2009年12月 |
| 5.1 | 2011年6月 |
| 2015 | 2015年6月 |
| 2016 | 2016年6月 |
| 2017 | 2017年6月 |

<!-- textlint-disable -->

ES5.1からES2015がでるまで6年もの歳月がかかっているの対して、ES2015以降は毎年リリースされています。
毎年安定したリリースを行えるようになったのは、ES2015以降は仕様策定プロセスの変更が行われたためです。

<!-- textlint-enable -->


## Living StandardとなるECMAScript

現在、ECMAScriptの仕様書のドラフトはGitHub上の[tc39/ecma262][]で管理されており日々更新されています。
そのため、本当の意味での最新のECMAScript仕様は<https://tc39.github.io/ecma262/>となります。
このように更新ごとにバージョン番号を付けずに、常に最新版を公開する仕様のことを**Living Standard**と呼びます。

ECMAScriptはLiving Stadardですが、これに加えてECMAScript 2017のようにバージョン番号をつけたものも公開されています。
このバージョン付きECMAScriptは、毎年決まった時期のドラフトを元にしたスナップショットのようなものです。

ブラウザなどに実際にJavaScriptとして実装される際には、Living StandardのECMAScriptを参照しています。
これは、ブラウザ自体も日々更新されるものであり、決まった時期にしかリリースされないバージョン付きよりもLiving Standardの方が適当であるためです。

## 仕様策定のプロセス

ES2015以前はすべての仕様の合意が取れるまで延々と議論を続けすべてが決まってからリリースされていました。
そのため、ES2015がリリースされるまでには6年もの歳月がかかり言語の進化が停滞していました。
この問題を解消するために、TC39は毎年リリースするためにECMAScriptの策定プロセスを変更しました。

この策定プロセスはES2015がリリース後に適応され、このプロセスで初めてリリースされたのがES2016となります。
ES2016以降では、次のような仕様策定のプロセスで議論を進めて仕様が決定されています。[^process]

仕様に追加する機能(API、構文など)をそれぞれ個別の**プロポーザル**(提案書)として進めていきます。
現在策定中のプロポーザルはGitHub上の[tc39/proposals][]に一覧が公開されています。
それぞれのプロポーザルは責任者である**チャンピオン**と**ステージ**(Stage)と呼ばれる`0`から`4`の5段階の状態を持ちます。

| ステージ | ステージの概要 |
| :------: | ------------------------------------------------------------ |
| 0 | アイデアの段階 |
| 1 | 機能提案の段階 |
| 2 | 機能の仕様書ドラフトを作成した段階 |
| 3 | 仕様としては完成しており、ブラウザの実装やフィードバックを求める段階 |
| 4 | 仕様策定が完了し、2つ以上の実装が存在している。<br />正式にECMAScriptにマージできる段階 |

2ヶ月に1度行われるTC39のミーティングにおいて、プロポーザルごとにステージを進めるかどうかを議論します。
このミーティングの議事録もGitHub上の[tc39/tc39-notes][]にて公開されています。
ステージ4となったプロポーザルはドラフト版である[tc39/ecma262][]へマージされます。
そして毎年の決まった時期にドラフト版を元にして`ECMAScript 20XX`としてリリースします。

この仕様策定プロセスの変更は、ECMAScriptに含まれる機能の形にも影響しています。

たとえば、`class`構文の策定は**最大限に最小のクラス**(maximally minimal classes)と呼ばれる形で提案されています。
これによりES2015で`class`構文が導入されましたが、クラスとして合意が取れる最低限の機能だけの状態で入りました。
その他のクラスの機能は別のプロポーザルとして提案され、ES2015以降に持ち越された形で議論が進められています。

このような合意が取れる最低限の形でプロポーザルを進めていくのには、ES4の苦い失敗が背景にあります。
ES4ではECMAScriptに多くの変更を入れることを試みましたが、TC39内でも意見が分かれ最終的に合意できませんでした。
これによりES4の策定に割いた数年分のリソースが無駄となってしまったという経緯があります。[^1]

ES2016以降の策定プロセスでも、すべてのプロポーザルが仕様に入るわけではありません。[^2]
別の代替プロポーザルが出た場合や後方互換性と保てない場合などにプロポーザルの策定を中断する場合があります。
しかし、この場合でもプロポーザルという単位であるため策定作業の無駄は最小限で済みます。
このようにモジュール化されたプロポーザルは入れ替えがし易いという性質もあります。

## プロポーザルの機能を試す

ECMAScriptの策定プロセスのステージ4に「2つ以上の実装が存在している」という項目があります。
そのためブラウザのJavaScriptエンジンには、策定中のプロポーザルが実装されている場合があります。
多くの場合は試験的なフラグ付きで実装されておりフラグを有効化することで、試すことができるようになっています。

またTranspilerやPolyfillといった手段で、プロポーザルの機能をエミュレートできる場合があります。

Transpilerとは、新しい構文を既存の機能で再現できるようにソースコードを変換するツールのことです。
たとえば、ES2015で`class`構文が導入されましたが、ES5では`class`は予約語であるため構文エラーとなり実行することはできません。
Transpilerでは、`class`構文を含むソースコードを`function`キーワードを使い擬似的に再現するコードへ変換します。
Transpilerとしては[Babel][]や[TypeScript][]などが有名です。

Polyfillとは、新しい関数やメソッドなどの仕様を満たすような実装を提供するライブラリのことです。
たとえば、ES2016では`Array#inclues`というメソッドが追加されました。
構文とは異なり`Array#inclues`のようなメソッドはビルトインオブジェクトを書き換えることで実装できます。
Polyfillを提供するものとしては[core-js][]や[polyfill.io][]などが有名です。

注意点としてはTranspilerやPolyfillはあくまで既存の機能で新しい機能を再現を試みているだけに過ぎません。
そのため、既存の機能で再現ができないプロポーザル(機能)はTranspilerやPolyfillでは再現できません。
また、完全な再現はできていないことがあるためTranspilerやPolyfillを新しい機能を学ぶために使うべきではありません。

<!-- Notes: バージョンが西暦となった理由

実際に各ブラウザなどはECMAScriptを実装していますが、このときに参照するのは基本的にLiving StandardであるECMAScriptです。
また、PolyfillやTranspilerといった手段で、タグ付けされたECMAScript 20XXがリリースされる前にその機能が利用できることも多いです。
ECMAScriptのバージョンとしてES6ではなくES2015のように西暦をバージョンとして使うようになったのも、Living Standardを意識しての試みです。

-->

## 仕様や策定プロセスを知る意味

こうしたECMAScriptという仕様や策定プロセスを知る意味は何があるのでしょうか?
主に次のような理由で知る意味があると考えています。

- 言語を学ぶため
- 言語が進化しているため
- 情報の正しい状態を調べるため

### 言語を学ぶため

もっとも単純な理由はJavaScriptという言語そのものを学ぶためです。
言語の詳細を知りたい場合にはECMAScriptという仕様を参照できます。

しかしながら、JavaScriptにおいては言語機能に関しては[MDN Web Docs][]という優れたリファレンスサイトなどがあります。
そのため、使い方を覚えたいなどの範囲ではECMAScriptの仕様そのものを参照する機会は少ないでしょう。

### 言語が進化しているため

ECMAScriptはLiving Standardであり、日々更新されています。
これは、言語仕様に新しい機能や修正などが常に行われていることを表しています。

ECMAScriptは後方互換性を尊重するため、今学んでいることが無駄になるわけではありません。
しかしながら言語自体も進化していることは意識しておくとよいでしょう。

ECMAScriptのプロポーザル(機能)は問題を解決するために提案されます。
そのプロポーザルがECMAScriptにマージされ利用できる場合、その機能が何を解決するために導入されたのか知ることは大切です。
その際には、ECMAScriptの策定プロセスを知っておくことが調べることに役立ちます。

この仕様はなぜこうなったのかということを知りたいと思ったときに、その機能がどのような経緯で入ったのかを調べる手段をもつことは大切です。
特にES2015以降は策定プロセスもGitHubを利用したオープンなものとなり、過去の記録なども探しやすくなっています。

### 情報の正しい状態を調べるため

JavaScriptは幅広く使われている言語であるため、世の中には膨大な情報があります。
そして、検索して見つかる情報には正しいものや間違ったものが混在しています。

その中においてECMAScriptの仕様やその策定中のプロポーザルに関する情報は状態が明確です。
基本的にECMAScriptの仕様に入ったものは、後方互換性を維持するために破壊的変更は殆ど行なえません。
プロポーザルはステージという明示された状態があり、ステージ4未満の場合はまだ安定していないことが分かります。

そのため、問題を見つけた際に該当する仕様やプロポーザルを確認してみることは重要です。

これはECMAScriptにかぎらず、ウェブやブラウザに関する情報に関しては同じことがいえます。
ブラウザ関してはHTML、DOM API、CSSなどもオープンな仕様とそれぞれ策定プロセスが存在しています。

### まとめ

JavaScriptと一言にいってもECMAScript、ブラウザ、Node.js、WebAssembly、WebGL、WebRTCなど幅広い分野があります。
そのためすべてのことを知っている必要はありませんし、知っている人もおそらくいないでしょう。
このような状況下においては知識そのものよりも、それについて知りたいと思ったときに調べる方法を持っていることが大切です。

なにごとも突然全く新しい概念が増えるわけではなく、ものごとには過程が存在します。
ECMAScriptにおいては策定プロセスという形でどのような段階であるかが公開されています。
つまり、仕様にいきなり新しい機能が増えるのではなくプロポーザルという段階を踏んでいます。

日々変化しているソフトウェアにおいては、自身に適切な調べ方をもつことが大切です。

[^1]: ES2015の仕様編集者であるAllen Wirfs-Brock氏の書いた[Programming Language Standardization](http://wirfs-brock.com/allen/files/papers/standpats-asianplop2016.pdf)に詳細が書かれています。
[^2]: [Inactive Proposals](https://github.com/tc39/proposals/blob/master/inactive-proposals.md)に策定を中止したプロポーザルの一覧が公開されています。
[^process]: この策定プロセスは<https://tc39.github.io/process-document/>に詳細が書かれています。
[^ES4]: ECMAScript 4は複雑で大きな変更が含まれており、合意を得ることできずに仕様策定が破棄されました。

[Ecma International]: http://www.ecma-international.org/ "Ecma International"
[Standard ECMA-262]: https://www.ecma-international.org/publications/standards/Ecma-262.htm "Standard ECMA-262"
[tc39/proposals]: https://github.com/tc39/proposals "tc39/proposals: Tracking ECMAScript Proposals"
[tc39/ecma262]: https://github.com/tc39/ecma262 "tc39/ecma262: Status, process, and documents for ECMA262"
[tc39/tc39-notes]: https://github.com/tc39/tc39-notes "tc39/tc39-notes: TC39 Meeting Notes"
[Babel]: https://babeljs.io/ "Babel · The compiler for writing next generation JavaScript"
[TypeScript]: https://www.typescriptlang.org/ "TypeScript - JavaScript that scales."
[core-js]: https://github.com/zloirock/core-js "zloirock/core-js: Standard Library"
[polyfill.io]: https://polyfill.io/v2/docs/ "Polyfill service"
[MDN Web Docs]: https://developer.mozilla.org/ja/ "MDN Web Docs"
4 changes: 2 additions & 2 deletions source/basic/function-this/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ console.log(fn()); // グローバルオブジェクト
fn.call({}); // グローバルオブジェクト
```

最初に述べたよう`function`キーワードで定義した関数は呼び出し時に、ベースオブジェクトが暗黙的な引数のように`this`の値として渡されます。
最初に述べたように`function`キーワードで定義した関数は呼び出し時に、ベースオブジェクトが暗黙的な引数のように`this`の値として渡されます。
一方、Arrow Functionの関数は呼び出し時に`this`を受け取らずに、定義時のArrow Functionにおける`this`の参照先が静的に決定されます。

<!-- textlint-disable -->
Expand Down Expand Up @@ -900,7 +900,7 @@ console.log(object.method.call("THAT")); // => "THAT"
コールバック関数における`this`はArrow Functionを使うことで分かりやすく解決できます。
この背景にはArrow Functionで定義した関数は`this`を持たないという性質があります。

[^awbjs]: ES 2015の仕様策定者であるAllen Wirfs-Brock‏氏もただの関数においては`this`を使うべきではないと述べている。<https://twitter.com/awbjs/status/938272440085446657>;
[^awbjs]: ES 2015の仕様編集者であるAllen Wirfs-Brock‏氏もただの関数においては`this`を使うべきではないと述べている。<https://twitter.com/awbjs/status/938272440085446657>;
[JavaScriptとは]: ../introduction/README.md
[関数と宣言]: ../function-declaration/README.md
[関数とスコープ]: ../function-scope/README.md
Expand Down
2 changes: 1 addition & 1 deletion test/techbooster.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ rules:
pattern: 綺麗
prh: 漢字で書かず、ひらがなで書くと読みやすくなります
- expected: こと
pattern: /(記|大|仕)?事(?!情|件|前|後|例|実|体|態|項)/
pattern: /(記|大|仕|議)?事(?!情|件|前|後|例|実|体|態|項|録)/
regexpMustEmpty: $1
prh: 漢字で書かず、ひらがなで書くと読みやすくなります
specs:
Expand Down