考虑这样的模式,我们想要为一个属性定义一个漂亮的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。我不是在寻找这样的解决方案,无论多么明显;这是一个假设的问题,关于是否可以在已定义的属性上定义属性。
答案 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函数中)。