ES6の前にES5のベストプラクティスを改めて考えたい
歴史認識
だいたい以下のような流れだと認識している。
- IE8以前を含むECMAScript 3暗黒時代があった
- この時代をベースにベストプラクティスが構築 + HTML5ブームが発生した
- 暗黒時代なんで結構つらいし、IE9じゃないとECMAScript 5使えないし、結局辛い
- CoffeeScriptを筆頭としたaltJS一派に救いを求めた(結局Coffeeは一過性のカフェインだったわけだけど)
- 気がついたらECMAScript 6が来そうになっていた
- ES6でのsyntaxの拡張・標準ライブラリの増強はカッコいい
- 気がついたらES5当たり前、ES6も使えそうな世界が来そうになっていた(希望的観測が多分に含まれているのは暗黙の了解と化している)
- ES6、altJSの次のナウい世界として注目を集める
だいたいこんな感じで、ECMAScript 5を用いたベストプラクティス的な物が存在しない、ないしは「全員知っている」という暗黙の了解の下に、明確な話があまり語られずに進んでしまっていると思います。
と、いうわけで、我々はreal productでいつ使えるか不明なES6 syntaxにこだわる前に、ES5を語るべきなのではないかと感じています(IE8以前も割と堂々と無視していい時代になったし)。
で、ES5でどうするの
前段では壮大な構想をぶっていましたが、ES5自体が過去の非互換・不明瞭な挙動を明確に定めたベースラインとしての性質を持っているので、あんまり語ることが無いというが現実とは思います。
use strict
を使え
すっかり定着した感はありますが、いいからstrict modeを使え。これが今後の基盤になる。
Object.seal
, Object.freeze
を積極的に使う
処理系によるJIT最適化時のhidden class (shape)の構造を安定化させる=最適化の余地を増やすという副次効果が存在しますが、そんなものは処理系が最適化パスを入れているか次第なので、ここでは主題とはしません。
この2種類のメソッドを利用するメリットは、オブジェクトの構造をstaticにすることで、予期せぬプロパティの追加や変更を防ぐ点にあります。これにより、単純なtypoによる想定外のプロパティ名の追加・参照や、Read Onlyとなるべき返り値の取り扱いが容易になります。
そして、strictモード環境下では、これらのメソッドを適用したオブジェクトへの不用意な操作に対してエラーを発生させるため、デバッガビリティの向上につながります(というよりもstrictモードが無いとエラーが出ないのでデバッガビリティが著しく低く、むしろ付けない方が良いケースがある)。
Object.preventExtension
でも同様にオブジェクト構造をstaticにすることが可能ですが、ECMAScript 5におけるlazy getterパターンとか使わない限りは、Object.seal
で問題ないと思います。
Object.defineProperty
でのsetter/getterの動的生成
Vue.jsあたりがこれでデータバインディングを実現していたと認識しているんですが(流し読みしたんで覚えてない)、それに限らず、便利なんで使いましょう。
Function.prototype.bind
による引数を部分適用した関数の生成
クロージャと違ってスコープまたいで束縛できて便利
Array
の拡張メソッド群
便利。かつてはパフォーマンス上の理由で使うべきではないとされていましたが、今時のエンジンはだいたいself-hostedしてるのでhotなコードであれば最適化可能だし、パフォーマンス的に忌避する理由はない。というよりも、パフォーマンス的にクリティカルな箇所はあとで計測時に発見されて問題になるので、そのときに考えた方が良い。
ES5で間に合わないこと
ES6 Promise
適当にpolyfillで解決しましょう
Module
requireJS使うなり、自分でconcatするなり、TypeScriptさまに全てを解決してもらえばいいのではないか
クラス構文
ES5にそんなものはない。プロトタイプベースで書け。だいたいなんとかなる。
定数宣言
TypeScriptがそこらへん検査・保証してくれるとうれしかった。
型アノテーション
Closure CompilerかTypeScript
総論
ES5でも結構まともに開発は可能です。
以上の理由から、筆者はaltJSに頼る必要性をあまり感じていません。
ただ、
あたりの理由から、TypeScriptの型アノテーション + モジュール機能あたりだけを使って、残りは全部ES5で書くくらいがいい塩梅なのではないかと感じています(TypeScriptの出力する、クラス構文のtrans-pileされたコードが個人的に好きではないというのもある)。
尚、個人的にはES7でTypedObjectの標準化はもちろん、型アノテーションくらいもついてくれると非常にうれしい。
最後に
正直、3年ほど書くのが遅れたという気持ちはある。