公開日: 2018-02-22 変更日: 2018-02-22 Download PDF

autoscale: true

ECMAScriptの使い方


自己紹介

アイコン right

  • 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のバージョンの歴史

right, fit, ecmascript-versions.png

  • ES5.1からES2015がでるまで4年もかかってる
  • ES2015以降は毎年リリースされている

fit, es-timeline.png


仕様策定のプロセスの変化

  • ES2015以前
    • すべての仕様の合意がとれてから一括リリース
  • ES2016以降
    • 合意がとれた仕様から順次リリース
  • ECMAScriptを毎年リリースするために策定プロセスを変更

ES2016以降の仕様策定プロセス

  • 仕様に追加する機能(API、構文など)をそれぞれ個別のプロポーザル(提案書)として進める
  • 現在策定中のプロポーザルはGitHUb tc39/proposalsにて公開
  • 各プロポーザルは責任者であるチャンピオンとステージ(Stage)と呼ばれる0から4の5段階の状態をもつ
    • チャンピオンが責任持ってプロポーザルを進める

プロポーザルのステージ

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

プロポーザルのステージの進み方

  • 2ヶ月に1度行われるTC39のミーティングでプロポーザルのステージを更新
  • ミーティングの議事録はGitHUb 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相当への変換と実行結果が異なる

inline, class


Babel(preset-envのデフォルト)

inline, babel


TypeScript(target:es5)

inline, typescript


例: BabelとTypeScriptのメソッドの列挙

  • Babelはメソッド(プロパティ)は列挙されないので []
  • TypeSdriptはメソッド(プロパティ)が列挙されるので ["method"]
  • どっちが正しいのかを仕様を調べてみる
    • *ネイティブで実行するのが最速の調べ方だけど、まあたまにバグってるので…

仕様の調べ方

  • 理由がなければ最新版を使う https://tc39.github.io/ecma262/
  • class構文のメソッド定義の仕方を調べたい

大きな流れ

  1. class というSyntaxの定義を探す
  2. classのRuntime Semantics(Syntaxにはそれぞれ実行時に何をするかという定義がある)
  3. Runtime Semanticsでそれぞれの method(){} がどのように定義されているかを見ていく
  4. 今回は列挙されているかなので enumerable を調べる

fit, class-definition.mp4


仕様を読んだまとめ

  • 動画で紹介したように仕様では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とは

right, fit

  • ES21015以降を基本としたJavaScriptの入門書
  • Living StandardであるECMAScriptに追従するように書いてる
  • github.com/asciidwango/js-primer
  • 興味ある人はWatchしておいてください

inline, repo-actions-watch.png


例: 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の値が静的に決まるという話にした
    • 詳細はECMAScript 2015以降のJavaScriptのthisを理解する | Web Scratch

例2: 関数とthisの表現 – thisの値


例2: 関数とthisの表現 – thisの値

  • thisの解説をするためにあらゆる場所のthisの挙動を調べていた
  • 次の"Module"の挙動がブラウザによって違った
    • V8はWindow、 その他はundefined
<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
    • ES6 moduleのtop levelにあるthisの値は何になるのか?
  • つまりはChrome/V8のバグ :bug:

例2: 関数とthisの表現 – thisの値

fit, right

  • thisのテーブル: azu.github.io/what-is-this
  • :bug: 報告: 791334 - this in top level Arrow Function in Module Context should be undefined - chromium - Monorail
  • Chrome 65で直る

:beginner: プロポーザルのステータスを知りたい

このプロポーザルの今のステータスは?


tc39/proposals: Tracking ECMAScript Proposals

proposals


babel/proposals: ✍️ Tracking the status of Babel's implementation of TC39 proposals

  • Babelの実装との対応表

right, fit, babel-proposals.png


このプロポーザルって進んでるの?

  • 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 サマリを見るのが簡単

right, decorators-agenda.png


inline, summary-decorator.png


例: 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で議論するべき課題があるかどうかを示している

inline, rockets.png


: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から読めます