1

考虑这样的模式,我们想为属性定义一个很好的 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 };
        }
    });
}

这让我们不必担心 id,因此我们可以像这样设置“事物”:

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

但是,当“事物”本身就是一个 getter/setter 时,如何定义这样的属性呢?如果需要的话,我习惯于在 JS 中为任何东西添加属性——函数、数组、冰淇淋甜筒等等。但在这种情况下似乎是不可能的,至少在我能想到的任何方面都是不可能的。

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

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

4

1 回答 1

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 将接受先前定义的值类型的属性作为其第一个参数。大概一个值属性被认为是一个真实的对象,而一个访问器属性是一个......幻像抽象?不管它是什么,在“它”存在之前(即在get 函数中),您都不能将事物固定到“它”上。

于 2014-03-26T23:10:47.807 回答