カラクリスタ

Objectオブジェクトのイテレーター

概要: 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