実装
仕様についてこの前調べた。
実装がどうなっているかも確認する。
Chrome
Chrome はそのままだとどのバーションでも、イテレータ関係の機能は全く使えない。chrome://flags/#enable-javascript-harmony
を有効にする必要がある。
Chrome 35.0.1916.153 stable だと V8 が 3.25.28.18 でarray.keys
、array.values
、array.entries
が存在する。for-ofはIterable
ではなくIterator
を渡す場合動く。つまり、for (var a of [0, 1, 2]) ...
はダメだけどfor (var a of [0, 1, 2].values())
なら期待通り動く。ジェネレータも動いた。
Chrome 38.0.2086.3 canary では V8 が 3.28.19 になってWeakMap、WeakSet以外はfor-ofもジェネレータもひと通り使えるようになっていた。かなりいいかんじ。
Node
Node でも--harmony
フラグを付けないとイテレータ関係の機能は使えない。
Node 0.10.29 は V8 が 3.14.5.9 で、一応Map
、Set
、WeakMap
のコンストラクタが存在する。ただし、イテレータ周りの実装はなくて全く使えない。
Node 0.11.13 では V8 は 3.25.30 になって、Symbol
、Array.keys
などが実装されfor-ofはIterable
じゃなくてIterator
を受け取る、Chrome 35 と同じような動作をする。ジェネレータも動いた。
Firefox
for-ofとArray
の@@iterator
は13の時から使えるらしい[参考]。Map
とSet
の@@iterator
は17から使える。ジェネレータも使えた。
Firefox 30 で確認したら、Array
、Map
、Set
はなぜかarray.values
はないのを除けばメソッドも含めて実装されていて、WeakMap
のコンストラクタも存在していた。
ただし、Symbol
が実装されたのは33かららしい[参考]。Iterable
なオブジェクトには、Symbol.iterator
ではなく'@@iterator'
という文字列をキーに使っている。
Firefox 33.0a1 nightly で確認したらSymbol
はあったけど、@@iterator
はまだ'@@iterator'
という文字列をキーに使っていた。おそらくこれから移行していくんだと思う。このバージョンでもarray.values
はなぜかない。
Safari/WebKit
Safari 7.0.5 はイテレータ関係は全くダメ。
Webkit nightly build 7.0.5 9537.77.4, r170987で確認したら、array.values
と[Symbol.iterator]
を除いて、Array
、Map
、Set
がメソッドも含めて実装されていた。ただし、array.keys
とかが返すオブジェクトが謎。next
とかのメソッドは存在しない。for-ofにはarray
とarray.keys
などが返すオブジェクトを渡すことができたけど、自分でIterable
とかIterator
を作って渡すのは無理だった。
なんか1番変な実装だった。Yosemiteで良くなるのかな?わからない。
IE
知らない
Transpilers
- regenerator
- ジェネレータをES5に変換する
- ジェネレータは
Symbol.iterator
があればそれを、なければ'@@iterator'
を使うっぽい。[参考]
- es6-transpiler
- ES6の構文をES5に変換する
- ジェネレータは未対応
- spread、for-of、array comprehensionsで
Iterable
なオブジェクトを使えるっぽい Symbol.iterator
があればそれを、なければ'@@iterator'
を使うっぽい[参考]
- ES6の構文をES5に変換する
- google/traceur-compiler
- ES nextをES5に変換する
Symbol
もMap
もSet
も面倒見てくれるWeakMap
とかはない- 実行環境が中途半端に実装していると、それ以上は面倒見てくれない
Symbol.iterator
を使う
Polyfills
- es6-map、es6-set
- それぞれ
Map
とSet
のpolyfill Symbol.iterator
があればそれを、なければ'@@iterator'
を使う
- それぞれ
- es6-shim
- いろんなオブジェクトのpolyfill
Symbol.iterator
があればそれを、なければ'_es6shim_iterator_'
を使う- ただし、Firefoxの場合は
'@@iterator'
を使う - 少し複雑
- ただし、Firefoxの場合は
まとめ
- 現状イテレータをそのまま使える処理系はなさそう
- そもそも実装されていなかったり、フラグが必要だったり
- for-ofとかジェネレータを使う場合transpilerが必要
- 中途半端に実装されている環境を考慮するといろいろつらい
- 自分の作ったライブラリをIterator対応させたい場合
iterator
メソッドを作って、それをSymbol.iterator
と'@@iterator'
に入れておくのがいいかもしれない
var AwesomeObject = function() {};
AwesomeObject.prototype.iterator = function(){
// iteratorを返す素晴らしい処理
};
if (typeof Symbol !== 'undefined' && Symbol.iterator)
AwesomeObject.prototype[Symbol.iterator] = AwesomeObject.prototype.iterator;
AwsomeObject.prototype['@@iterator'] = AwesomeObject.prototype.iterator;
AwsomeObject.prototype['_es6shim_iterator_'] = AwesomeObject.prototype.iterator;