ぶれすとつーる

だいたいjavascript

Proxyでオブジェクトにlength

ある日、会社で「オブジェクトにlengthプロパティが欲しい」といわれたので色々考えてみました。。

lengthプロパティはArrayオブジェクトとかに存在するあれです。

var ary = ["a", "b", "c"];
console.log(ary.length); // output: 3

これを普通のオブジェクトにも欲しいといわれました。

理想はこんな感じらしい。

/* error */
var obj = {
    'a': 1,
    'b': 2,
    'c': 3
};
console.log(obj.length); // output: 3

てっとりばやく関数化するとこんな感じ。

Object.prototype.length = function () {
    var i = 0, prop;
    for (prop in this) {
        if (this.hasOwnProperty(prop)) i++;
    }
    return i;
};

var obj ={a:1, b:2};

console.log(obj.length()); // output: 2

E4Xとかのlengthはメソッドになっててちょうどこんな感じの呼び出しなので僕は特に違和感はないのですがこういうのってES.nextProxyでArrayのlengthっぽくできるなって感じたので実装してみました。

/* only ff4 over */
var obj = Proxy.create({
    get: function (p, name) {
        var i = 0, prop, data = this.data;
        if (name != 'length') return data[name];
        for (prop in data) {
            if (data.hasOwnProperty(prop)) i++;
        }
        return i;
    },
    set: function (p, name, val) {
        this.data[name] = val;
    },
    data: {}
});

obj["a"] = 1;
obj["b"] = 2;
console.log(obj.length); // output: 2

こんな感じ。
ProxyES.nextで草案としてあげらてるもので、FF4以上は先行実装という形で実装しているのでFF4以上限定で使えます。


getter, setterがあっていい感じですね


Proxyは今あげられてる草案の中でもかなりいい感じの仕様だとおもいます



追記

@teramako さんがはてぶでコメントをくださったので追記します。


Object.defineProperty(Object.prototype, "__count__", { configurable: true, get: function(){ return Object.keys(this).length; } }) ではダメ?

ぎくり。。まぬけな投稿をしてしまった。。

javascript1.8.5からObject.definePropertyでオブジェクトのプロパティを定義するとgetter経由で値が取得できます。

Object.defineProperty(Object.prototype, "__count__", {
    configurable: true,
    get: function() {
        return Object.keys(this).length;
    }
});

var obj = {
    a: 1,
    b: 2
};

console.log(obj.__count__); // output: 2

こっちのほうが全然すっきりしてますね。

Object.keys(this).length とか超エレガントですごーです。

@teramako さんご教授ありがとうございます!