在已定义的属性上使用Object.defineProperty

时间:2014-03-26 21:59:40

标签: javascript defineproperty

考虑这样的模式,我们想要为一个属性定义一个漂亮的getter / setter接口来隐藏一些内部验证:

var validThings = {
    'pretty name a': 3293293,
    'pretty name b': 8275850,
    'pretty name c': 2983855
};


function Constructor() {
    var internalThing = {
        name: 'pretty name a',
        id: '3293293'
    };

    Object.defineProperty(this, 'thing', {
        get: function() { return internalThing.name; },
        set: function(val) {
            var id = validThings[val];
            if (id) internalThing = { name: val, id: id };
        }
    });
}

这让我们可以避免担心ids,所以我们可以像这样设置“东西”:

var constructoid = new Constructor();
constructoid.thing = 'pretty name b';
constructoid.thing; // 'pretty name b';

当然,它阻止我们将其设置为无效值:

constructoid.thing = 'pretty name d';
constructoid.thing; // 'pretty name b';

但是,假设我们确实希望能够从对象外部访问ID。最自然的界面将是物品的属性

constructoid.thing.id

但是,当'thing'本身就是一个getter / setter时,如何定义这样的属性呢?我习惯于能够在任何需要的东西上抛出属性,在JS中 - 函数,数组,冰淇淋锥等等。但在这种情况下似乎是不可能的,至少不是我能想到的任何方式。

Object.defineProperty(this.thing, 'id', {...}) // <-- error

当然,我可以简单地在Constructor对象本身上定义一个属性,比如'thingID',或者我可以从thing getter返回名称和ID。我不是在寻找这样的解决方案,无论多么明显;这是一个假设的问题,关于是否可以在已定义的属性上定义属性。

1 个答案:

答案 0 :(得分:0)

我找到了一种方法:

    Object.defineProperty(this, 'thing', {
        get: function() {
            var name = internalThing.name;
            if (!name) return;
            name = new String(name);
            Object.defineProperty(name, 'id', {
                get: function() { return internalThing.id; }
            });
            return name;
        },
        set: function(val) {
            var id = validThings[val];
            if (id) internalThing = { name: val, id: id };
        }
    });

我之前从未有过使用String构造函数的机会,但事实证明它允许您向特定字符串添加属性。如果有人有更好的方法,我仍然对实现这种效果的其他方法感到好奇。


编辑:

正如Felix Kling所指出的,String作为构造函数太麻烦了。如果第一个getter返回的值不是原始的,那么上述模式可以正常工作,因此它在某些情况下可能很有用,但对于原语我不认为有任何好的解决方案。对于值属性,对象要求也是如此 - 尽管与访问器不同,defineProperty将接受先前定义的值类型作为其第一个参数。大概是一个值属性被认为是一个真实的对象,而一个访问属性是一个......幻象抽象?不管它是什么,你都可以把东西钉在它的上面。直到&#39;它&#39;存在(即在get函数中)。