Firefox 17 から Map と Set がイテラブルになった件について
さて、Firefox 17 がリリースされました。そのリリースノートに、以下の様なのがあります。
JavaScript の Maps と Sets がイテラブル (反復可能なオブジェクト) として利用できるようなりました。
これはどういうことなのかを少し解説。といっても、内部のECMAScript仕様に詳しいわけではないので、その辺りは、Constellationさんに譲りたいと思います(ぉ あくまでMozilla実装での使い方ということで。
var map = new Map([ ["a", "A"], ["b", "B"] ]); map.set("c", "C"); console.log( map.get("a"), map.get("b"), map.get("c") ); // "A B C"
ここまでは今までの基本です。
イテラブルとは
では、イテラブル*1とはどういうことか。
失敗例
for (var key in map) { console.log(key); }
これは失敗です。for-in構文で回せるわけではありません。
for-of構文を使います。
for (var v of map) { console.log("%s: %s", v[0], v[1]); } /* a: A b: B c: C */ // 以下の様に分割代入を使うのが良い感じ for (var [key, value] of map) { console.log("%s: %s", key, value); } /* a: A b: B c: C */
という具合です。
for-of 構文をもう少し突っ込んでみる
さて、for-of構文というと、配列とかHTMLCollection,NodeListに使うものでした。
単なるObjectに使うと....
var obj = { a: "A", b: "B" }; for (var value of obj) { console.log(value); } // TypeError: obj is not iterable
TypeError: obj is not iterable
を例外が発生してしまい、単純なObjectにはfor-ofは使えないことが分かります。
ところで、Object.getOwnPropertyNames(Map.prototype)
でメソッド一覧を見てみると、iterator
という見慣れないメソッドを発見できます。*2
実はこのメソッドがあるとfor-ofで使えるようになるのです。ただし、ECMAScript.next のドラフト仕様を見てもiteratorの事は載っておらず、今後載るのかもしれませんが、Mozilla独自仕様の可能性があります。
// enumrable: false で iterator メソッドを定義 Object.defineProperty(Object.prototype, "iterator", { value: function() { for (var key of Object.keys(this)) { yield [key, this[key]]; } // 実はこの場合は return Iterator(this); でも可 }, configurable: true, writable: true, enumerable: false }); var obj = { a: "A", b: "B", c: "C" }; for (var [key, value] of obj) { console.log("obj %s: %s", key, value); } /* obj a: A obj b: B obj c: C */
iteratorメソッドにはyieldを使わないとうまいこと動作しないことに注意してください。
応用すれば、以下の様な事も可能でしょう。あまり副作用を考えてませんが(ぉ
Object.defineProperty(HTMLElement.prototype, "iteratror", { value: function() { var attrs = this.attributes; for (var i = 0, len = attrs.length; ++i) { yield [attrs[i],name, attrs[i].value]; } }, configurable: true, writable: true }); var elem = document.getElementById("foo"); for (var [attrName, attrValue] of elem) { // ... }