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
.
这使您可以使用所需的全能 getter 和 setter 功能创建一个对象:
"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 = bar
请注意,当我们尝试检索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...
};
但同样,我无法想象您真的想要这样做,因为它会改变您使用对象的方式。