概要: 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 オブジェクトでもできそう。
ちなみに上記コード、一部しかテストしてないため、ちゃんと動くかどうか不明。 そこをさぼってどうするのとか思うわけだけど、実装サンプルなのでそのあたり手抜き。
とりあえずアイディアだけまとめてみた。何につかえるんだろ。
#FIXME