2013 年和 2015 年更新 (请参阅下面的 2011 年原始答案):
这在 ES2015(又名“ES6”)规范中发生了变化:JavaScript 现在有 proxies。代理允许您创建真正代理其他对象(立面)的对象。下面是一个简单的示例,它可以在检索时将字符串中的任何属性值全部大写:
"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 是应该在 getter 函数中用作 this 的对象。在正常情况下,这是代理或继承自它的东西,但它可以是任何东西,因为陷阱可能由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 没有包罗万象的属性功能。您使用的访问器语法包含在规范的Section 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...
};
但同样,我无法想象您真的想这样做,因为它会改变您使用对象的方式。