カラクリサイクル

『輝かしい青春』なんて失かった人の雑記

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オブジェクトでもできそう。

ちなみに上記コード、一部しかテストしてないため、ちゃんと動くかどうか不明。 そこをさぼってどうするのとか思うわけだけど、実装サンプルなのでそのあたり手抜き。

とりあえずアイディアだけまとめてみた。何につかえるんだろ。