概要: Object オブジェクトのイテレーターを実装する。
Javascript にはハッシュが無い。とはいっても Object オブジェクトをハッシュのように使えるんだけど、
Object.prototype
を拡張すると空の Object まで汚染されるし、
Object.prototype
に Object のイテレーターを追加すると、
オブジェクトのキーにイテレーター名が使えなくなってしまう。
(Object.prototype.forEach
が実装されていたとすると、object **_forEach*_**
が定義されている Object では動かなくなる)
じゃあどうしたらいいんだろう、と思っていたんだけど、イテレータと Object を分離してやればいいんじゃないか、 と言うのを今日ふと思いついた。
実際の実装はこんな感じ。
Object.Iterator = function ( target ) { if ( typeof(target) != 'object' ) throw new TyprError('Arguments is not object.'); var self = this; self.target = function () { return target; } } Object.Iterator.prototype = { 'filter' : function ( callback, thisObject ) { if ( typeof(callback) != 'function' ) throw new TypeError('callback is not function'); var obj = this.target(), result = {}; for ( var key in obj ) { if ( obj.hasOwnProperty(key) ) { if ( callback.call(thisObject, key, obj [[key]] , obj) ) { result [[key]] = obj [[key]] ; } } } return result; }, 'each' : function ( callback, thisObject ) { if ( typeof(callback) != 'function' ) throw new TypeError('callback is not function'); var obj = this.target(); for ( var key in obj ) { if ( obj.hasOwnProperty(key) ) { callback.call(thisObject, key, obj [[key]] , obj); } } }, 'map' : function ( callback, thisObject ) { if ( typeof(callback) != 'function' ) throw new TypeError('callback is not function'); var obj = this.target(), result = {}; for ( var key in obj ) { if ( obj.hasOwnProperty(key) ) { result [[key]] = callback.call(thisObject, key, obj [[key]] , obj); } } return result; }, 'every' : function ( callback, thisObject ) { if ( typeof(callback) != 'function' ) throw new TypeError('callback is not function'); var obj = this.target(); for ( var key in obj ) { if ( obj.hasOwnProperty(key) && ! callback.call( thisObject, key, obj [[key]] , obj ) ) { return false; } } return true; }, 'some' : function ( callback, thisObject ) { if ( typeof(callback) != 'function' ) throw new TypeError('callback is not function'); var obj = this.target(); for ( var key in obj ) { if ( obj.hasOwnProperty(key) && callback.call( thisObject, key, obj [[key]] , obj ) ) { return true; } } return false; }, 'keys' : function () { var obj = this.target(), results = []; for ( var key in obj ) { if ( obj.hasOwnProperty(key) ) results [[results.length]] = key; } return results; }, 'values' : function () { var obj = this.target(), results = []; for ( var key in obj ) { if ( obj.hasOwnProperty(key) ) results [[results.length]] = obj [[key]] ; } return results; } };
で、こうやって使う。
var hash = { 'aaa': 'AAA', 'bbb': 'BBB', 'ccc': 'CCC' }; var iterator = new Object.Iterator( hash ); iterator.keys() // [[ 'aaa', 'bbb', 'ccc' ]]
こうすれば、Object オブジェクトを本当のハッシュのように使えると思う。 オブジェクトとイテレーター分離するっていうのは Array オブジェクトでもできそう。
ちなみに上記コード、一部しかテストしてないため、ちゃんと動くかどうか不明。 そこをさぼってどうするのとか思うわけだけど、実装サンプルなのでそのあたり手抜き。
とりあえずアイディアだけまとめてみた。何につかえるんだろ。