2013年和2015年更新 (请参阅下面的2011年原始答案):
从ES2015(又称“ ES6”)规范开始,此更改已更改:JavaScript现在具有代理。代理使您可以创建真正的对象(作为其他对象的门面)。这是一个简单的示例,可将字符串形式的所有属性值转换为检索时的所有大写字母:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
"foo": "bar"
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
});
console.log(`original.foo = ${original.foo}`); // "original.foo = bar"
console.log(`proxy.foo = ${proxy.foo}`); // "proxy.foo = BAR"
您未覆盖的操作具有其默认行为。在上面,我们要覆盖的全部是get
,但是有一个可以挂接的操作的完整列表。
在get
处理程序函数的参数列表中:
target
是要代理的对象(original
在本例中为)。
name
(当然)是要检索的属性的名称,通常是一个字符串,但也可以是一个符号。
receiver
this
如果属性是访问器而不是数据属性,则是应该在getter函数中使用的对象。在正常情况下,这是代理或继承自代理的东西,但是可以是任何东西,因为陷阱可能由触发Reflect.get
。
这使您可以使用所需的全部获取器和设置器功能创建对象:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.foo = ${obj.foo}`);
obj.foo = "bar";
console.log(`[after] obj.foo = ${obj.foo}`);
上面的输出是:
获取不存在的属性“ foo”
[之前] obj.foo =未定义
设置不存在的属性'foo',初始值:bar
[之后] obj.foo =条
请注意,当我们尝试检索foo
尚不存在的消息以及创建它时(而不是之后创建)时,如何获取“不存在”消息。
2011年的答案 (请参见上面的2013年和2015年更新):
不,JavaScript不具有全部属性功能。规范的第11.1.5节介绍了您使用的访问器语法,并且不提供任何通配符或类似的内容。
您当然可以实现一个函数来执行此操作,但是我猜测您可能不想使用f = obj.prop("foo");
而不是f = obj.foo;
和(obj.prop("foo", value);
而不是)obj.foo = value;
(对于该函数而言,处理未知属性是必需的)。
FWIW,getter函数(我不关心setter逻辑)看起来像这样:
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
但是再次,我无法想象您真的想要这样做,因为它如何改变您使用对象的方式。