autoscale: true
ECMAScriptの使い方
自己紹介
- Name : azu
- Twitter : @azu_re
- Website: Web scratch, JSer.info
- :zap: ECMAScript Daily
アジェンダ
- ECMAScriptとは何か
- ECMAScriptの使い方の事例
- 自律的にECMAScriptについての情報を検索できるようになる
以前の話したもの
- ECMAScript as a Living Standard
- ECMAScriptは毎年更新されるし、最新版はGitHubで毎日更新されてる
- Living Standardになってるよ
という話
ECMAScriptとは
- ECMAScriptはEcma Internationalという団体によって標準化されている仕様
- Ecma内のTC39という技術委員会によって、どのような機能を仕様へ入れるかを議論、決定
- TC39はMicroSoft、Mozilla、Google、Appleといったブラウザベンダーや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月 |
ECMAScriptのバージョンの歴史
- ES5.1からES2015がでるまで4年もかかってる
- ES2015以降は毎年リリースされている
仕様策定のプロセスの変化
- ES2015以前
- すべての仕様の合意がとれてから一括リリース
- ES2016以降
- 合意がとれた仕様から順次リリース
- ECMAScriptを毎年リリースするために策定プロセスを変更
ES2016以降の仕様策定プロセス
- 仕様に追加する機能(API、構文など)をそれぞれ個別のプロポーザル(提案書)として進める
- 現在策定中のプロポーザルは tc39/proposalsにて公開
- 各プロポーザルは責任者であるチャンピオンとステージ(Stage)と呼ばれる
0
から4
の5段階の状態をもつ- チャンピオンが責任持ってプロポーザルを進める
プロポーザルのステージ
ステージ | 名前 | ステージの概要 |
---|---|---|
0 | Strawman | アイデアの段階 |
1 | Proposal | 機能提案の段階 |
2 | Draft | 機能の仕様書ドラフトを作成した段階 |
3 | Candidate | 仕様としては完成しており、ブラウザの実装やフィードバックを求める段階 |
4 | Finished | 仕様策定が完了し、2つ以上の実装が存在している。テストがある。 正式にECMAScriptにマージできる段階 |
プロポーザルのステージの進み方
- 2ヶ月に1度行われるTC39のミーティングでプロポーザルのステージを更新
- ミーティングの議事録は tc39/tc39-notesで公開
- 毎年のECMAScriptをリリースするタイミング(6月)で、Stage 4のプロポーザルをマージ
ECMAScript 20XX
としてリリース
なぜ仕様策定プロセスが変わったのか
- ES2015以前: すべての仕様の合意が取れてからリリース
- ES2016以降: 合意が取れた仕様からリリース
- 変更理由: ECMAScriptのリリースに長い歳月がかかり言語の進化が停滞した
- 歴史的失敗: ES4では多くの変更を入れることを試みたが、TC39内でも意見が分かれ最終的に合意できなかった
- これにより言語の発展が数年間停滞した[^1]
[^1]: Programming Language Standardization: Patterns for Participationを参照
仕様策定プロセス変更の影響
- ECMAScriptに入れようとする機能(プロポーザル)の形も変化した
- 最大限最小(maximally minimal)のプロポーザル
- 最初からすべて入れることは無理なので、最小限の形から入れる提案が増えた[^2]
- すべてのプロポーザルが入るわけではない
- 代替のプロポーザルや後方互換性、ユースケースの問題で取り下げたプロポーザルも多い
- これはモジュール化されたプロポーザルは交換可能な事を表してる
[^2]: クラス、mixinなどがこのようなmaximally minimalで進んでいる
プロポーザルをエミュレート
- Stage 4に「2つ以上の実装が存在している」という必須要件がある
- 正式なECMAScriptになる前にはブラウザには実装される[^flag]
- TranspilerやPolyfillを使ってエミュレートできる
- Transpiler: 新しい構文を既存の機能で再現できるようにソースコードを変換するツール
- TypeScript、Babelなど
- Polyfill: プロポーザルで追加された新しいメソッドや関数などを実装を提供するライブラリ
- core-js、babel-polyfillなど
[^flag]: 多くはフラグ付き実装。一度Stableに入れると外せなくなるため。Stage 4の要件はあえて曖昧性を持たせている
:warning: TranspilerやPolyfillの注意 :warning:
- TranspilerやPolyfillはあくまで既存の機能で新しい機能を再現を試みているだけ
- 原理的に全く新しい機能は既存の機能では再現できない
- コストの問題で再現してないこともある
- TranspilerやPolyfillをそのプロポーザルを学ぶために使うべきではない
- 先行して試せるようになったというのが大きい、プロポーザルへのフィードバックができる
Living StandardとなるECMAScript
- ECMAScriptの仕様書のドラフトはGitHub上のtc39/ecma262で管理されている
- 本当の意味での最新のECMAScript仕様はhttps://tc39.github.io/ecma262/
- バージョン番号を付けずに、常に最新版を公開する仕様のことをLiving Standardと呼ぶ
- 加えて、ECMAScript 2017のようにバージョン番号をつけたものも公開
- バージョン付きECMAScriptは、スナップショットのようなもの
[fit] 仕様や策定プロセスを知る意味
仕様や策定プロセスを知る意味
- 言語を学ぶため
- 言語が進化しているため
- 情報の正しい状態を調べるため
言語を学ぶため
- JavaScriptという言語そのものを学ぶため
- 言語の詳細を知りたい場合にはECMAScriptという仕様を参照する
- JavaScriptにおいては言語機能に関してはMDN Web Docsなどで大抵は十分
言語が進化しているため
- 言語が進化しているのは何かの問題を解決するため
- ECMAScriptはLiving Standardであり、言語仕様に新しい機能や修正などが日々行われている
- ECMAScriptは後方互換性を尊重するため、今学んでいることが無駄になるわけではない
- この仕様はどのような経緯で入ったのかを調べる手段として策定プロセスを知る
- 特にES2015以降はGitHubに殆どの情報があるので探しやすい
情報の正しい状態を調べるため
- JavaScriptは幅広く使われている言語であるため、世の中には膨大な情報がある
- 検索して見つかる情報には正しいものや間違ったものが混在する
- JSer.infoはこの問題を解決するために作った
- 検索できる情報と比較: 仕様やプロポーザルに関する情報は状態が明確
- 仕様は安定。プロポーザルはステージという明示された状態があり、ステージ4未満の場合はまだ安定してない
- 問題を見つけた際に該当する仕様やプロポーザルなどよりオリジンに近いものを調べる手段を知る
^ これはECMAScriptにかぎらず、ウェブやブラウザに関する情報に関してはほぼおなじことがいえます。 ブラウザ関してはHTML、DOM API、CSS、IEFTなどもオープンな仕様とそれぞれ策定プロセスが存在しています。 これは今風の書き方といった煽りを避けるために必要な考え方。 先ほども書いたように新しい構文や機能が増えるのは何か問題があって解決したいから。 言語レベルで解決する必要ないなら言語に載せることはないし、何事もバランスが大事になる
具体例
:beginner: 実装が仕様に準拠しているかを調べたい
この挙動って仕様なの?というのをすべてのJavaScriptエンジンで比較する
eshost
- GoogleChromeLabs/jsvu: JavaScript (engine) Version Updater
- 主要なJavaScriptエンジンをまとめてインストール
- macOSならChakraを含めてほぼ対応できる
- bterlson/eshost-cli: Run ECMAScript code uniformly across any ECMAScript host
- 指定したJavaScriptエンジンでコードを実行できる
eshost
の実行例
$ eshost -e 'new RegExp("\n").toString()'
#### Chakra
/\n/
#### SpiderMonkey
/\n/
#### JavaScriptCore
/\n/
#### V8
/
/
:beginner: ECMAScriptの仕様を読む
例: BabelとTypeScriptのクラス
BabelとTypeScriptでES5相当への変換と実行結果が異なる
Babel(preset-envのデフォルト)
TypeScript(target:es5)
例: BabelとTypeScriptのメソッドの列挙
- Babelはメソッド(プロパティ)は列挙されないので
[]
- TypeSdriptはメソッド(プロパティ)が列挙されるので
["method"]
- どっちが正しいのかを仕様を調べてみる
- *ネイティブで実行するのが最速の調べ方だけど、まあたまにバグってるので…
仕様の調べ方
- 理由がなければ最新版を使う https://tc39.github.io/ecma262/
class
構文のメソッド定義の仕方を調べたい
大きな流れ
class
というSyntaxの定義を探すclass
のRuntime Semantics(Syntaxにはそれぞれ実行時に何をするかという定義がある)- Runtime Semanticsでそれぞれの
method(){}
がどのように定義されているかを見ていく - 今回は列挙されているかなので
enumerable
を調べる
仕様を読んだまとめ
- 動画で紹介したように仕様では
enumerable
をfalse
にしてメソッドを定義している - Babelは仕様に準拠するたびにdefinePropertyで列挙しないように(
enumerable
をfalse
)定義してる - TypeScriptは単純にプロトタイプオブジェクトのメソッドを追加してるだけなので列挙される
- 単純なプロパティ定義は
enumerable
をtrue
で定義される Object.keys
で列挙されるのはその違い
- 単純なプロパティ定義は
- Method class enumerable · Issue #15038 · Microsoft/TypeScript
補助資料
- How to Read the ECMAScript Specification
- ECMAScriptの読み方について解説してる
[[内部プロパティ]]
やAbstract Operator、Runtime semanticsなど仕様書に出てくる記号や読み方を解説してる
- anba/es6draft: ECMAScript 2015 (ECMA-262 6th Edition) compiler and runtime
- ECMAScriptのJava実装
- リファレンス実装的に仕様書と対応したアルゴリズムステップで実装されているので読みやすい
- ClassDefinitionEvaluationの実装もそのままある
例: js-primerの場合
js-primerとは
- ES21015以降を基本としたJavaScriptの入門書
- Living StandardであるECMAScriptに追従するように書いてる
- github.com/asciidwango/js-primer
- 興味ある人はWatchしておいてください
例: js-primerの場合
- 迷った場合はECMAScriptを参照する
- 用語、表現、動作の説明など
例1: 関数とthisの表現 – Arrow Function
function
キーワードで定義した関数は呼び出し時に、ベースオブジェクトが暗黙的な引数のようにthis
の値として渡されます。
一方、Arrow Functionの関数は呼び出し時にthis
を受け取らないため、定義時のArrow Functionにおけるthis
の参照先が静的に決定されます。
-- 関数とthis · JavaScriptの入門書 #jsprimer
例1: 関数とthisの表現 – Arrow Function
- 「Arrow Functionは
this
をbindする」という説明だと仕様に即していないため避けた - 仕様ではArrowFunctionは
[[ThisValue]]
を持たないLexicalEnvironmentという定義- つまり原理的に
this
そのものを持っていない
- つまり原理的に
- Arrow Functionは
this
の値を受け取らないからthis
の値が静的に決まるという話にした
例2: 関数とthisの表現 – this
の値
例2: 関数とthisの表現 – this
の値
this
の解説をするためにあらゆる場所のthis
の挙動を調べていた- 次の"Module"の挙動がブラウザによって違った
- V8は
Window
、 その他はundefined
- V8は
<script type="module">
const fn = () => this;
console.log(fn());
</script>
`
例2: 関数とthisの表現 – this
の値
- Arrow Functionにおける
this
は外側のスコープのthis
を参照する - トップレベルの
this
とトップレベルのArrow Functionにおけるthis
は同じ- 以下のコードは全ブラウザ同じ挙動だった
<script type="module">
const fn = () => this;
console.log(fn() === this); // => true
</script>
`
例2: 関数とthisの表現 – this
の値の仕様
- トップレベルの
this
の値は実行コンテキストによって違う - 実行コンテキストは"Script"と"Module"(いわゆるES moduleのコンテキスト)
- 仕様では"Module"コンテキストのトップレベル
this
は常にundefined
- つまりはChrome/V8のバグ :bug:
例2: 関数とthisの表現 – this
の値
this
のテーブル: azu.github.io/what-is-this- :bug: 報告: 791334 -
this
in top level Arrow Function in Module Context should beundefined
- chromium - Monorail - Chrome 65で直る
:beginner: プロポーザルのステータスを知りたい
このプロポーザルの今のステータスは?
tc39/proposals: Tracking ECMAScript Proposals
babel/proposals: ✍️ Tracking the status of Babel's implementation of TC39 proposals
- Babelの実装との対応表
このプロポーザルって進んでるの?
- ECMAScriptのプロポーザルにはそれぞれチャンピオンがいる
- チャンピオンがステージを進めたい :rocket: という意志が必要
- プロポーザルは勝手には進まない
- 何が課題で止まっているかプロポーザルリポジトリのIssueかミーティングノートを見る
例: tc39/proposal-global
global
でグローバルオブジェクトを取得するプロポーザル
例: tc39/proposal-global
- 2018年2月の段階ではStage 3で止まっている
- 理由はREADMEに書いてある
- global breaks flickr.com · Issue #20 · tc39/proposal-globalでは
global
という名前によって壊れるサイトがいる問題がありこれを理由に止まっている
however, due to web compatibility concerns, it is on hold pending a new global identifier name.
Tips :star:
- プロポーザルはそれぞれGitHubリポジトリを持っている
- プロポーザルのIssueには課題が書かれている
- ウェブ互換性の問題については基本的にメトリクスデータを元に話を進める
- 壊れるウェブサイトはn%あるか
- Chrome Platform Status、Microsoft Edge Platform Data、Firefox Data
例: tc39/proposal-decorators
@デコレーター
例: tc39/proposal-decorators
- 2018年2月の段階ではStage 2
- ECMAScript proposal updates @ 2016-07 | ECMAScript Dailyによると2016年からずっとStage 2のまま
- 何が原因で進んでないのかを調べる
- => TC39のミーティングでどのような議論が行われてるのかを調べる
- => 何が課題となっているかが話し合われているはず
例: tc39/proposal-decorators Stage 2
- tc39/agendas(議事録のアジェンダ)を"Decorators"で検索
- 定期的に議論されているので何か課題があり進んでいない
- Stage 3に進むには仕様としてひとまず完成した状態が求められる
- アジェンダと同じ月のミーティングノートを見る
- 2018-01/summary.md サマリを見るのが簡単
例: tc39/proposal-decorators Stage 3に向けて
- 13.v.c Decorators: towards Stage 3という議論が2018年1月に行われている
- Decorators: Towards Stage 3 - Google スライド
- Stage 3に向けて何をサポートし、何をサポートしないかをはっきりさせる
- 他のクラスのプロポーザル(hard private)との協調性についての課題があり調整している
- 実装者、テスト作成者、ライブラリ作者に対しても意見を求めてる
- 次のミーティング(3月)までにステークホルダーにアプローチする
Tips :star:
- Stage 1はまでアイデアや実験なのでプロポーザル間でも重複する
- Stage 2+あたりからプロポーザル間での協調的な仕様を検討する[^note]
- Decoratorはclass field、privateなど色々関係する
- 最近のDecoratorの変更は他のプロポーザルとの協調性やDecoratorが目指す範囲を確定する作業
- 今まで雰囲気で動いてた部分を明示的に例外を投げるようにするなど
[^note]: Revisiting mixins-vs-protocols proposalを参照
:rocket: はプロポーザルのStageをChampionが進める意志がある状態か(参考程度) まだそのStageで議論するべき課題があるかどうかを示している
:beginner: プロポーザルのステータスの変化を知りたい
プロポーザルのステータスの変更のタイミングを知りたい。通知欲しい
プロポーザルのステータスの変化を知りたい
- ECMAScript Daily
- ECMAScript関係のニュースブログ(@azu)
- EcmaScript.in | Stay updated about EcmaScript proposal changes
- プロポーザルのStage変化の通知メール
- 2ality – JavaScript and more
- プロポーザルの解説
- bevacqua/prop-tc39: Scraping microservice for TC39 proposals 😸
- API
今日話したこと
- ECMAScript · JavaScriptの入門書 #jsprimer
- js-primerに文章版があるよ
- @EcmascriptDailyをフォローしておけばとりあえず流れてくる
- ECMAScriptのプロポーザルはtc39/tc39-notes、tc39/proposals、各リポジトリを見れば殆どの情報があるよ
- 必要になったときに自分で探してみてください
まとめ
- :boom: JavaScript is ECMAScript、Browser、Node.js、WebAssembly、WebGL、WebRTC...
- :beginner: すべてのことを知る必要はなく、すべてを知っている人もいない
- :mag: 知りたいと思ったときに調べる方法を持っていることが大切
- :alien: なにごとも突然に新しい概念は増えない – 過程がある
- :star2: 日々変化するソフトウェアにおいては、自身に適切な調べ方をもつ
宿題 :house:
- ES2018で何が入るかをtc39/proposalsから探してみよう
- Hint: ES2018入るのはStage 4(Finished Proposals)
- 気になっているプロポーザルのリポジトリをWatchしよう
- Hint: プロポーザルの一覧はtc39/proposalsを見る
- ミーティングのサマリを読んでみよう
- 2018-01/summary.mdから読めます