我知道如何通过执行以下操作来为名称已经知道的属性创建getter和setter:
// A trivial example: function MyObject(val){ this.count = 0; this.value = val; } MyObject.prototype = { get value(){ return this.count < 2 ? "Go away" : this._value; }, set value(val){ this._value = val + (++this.count); } }; var a = new MyObject('foo'); alert(a.value); // --> "Go away" a.value = 'bar'; alert(a.value); // --> "bar2"
现在,我的问题是,是否可以定义像这样的所有获取方法和设置方法?即,创建getter和setter的任何属性名称 是不是 已经定义。
这个概念可以在PHP中使用__get()和__set()魔术方法(有关这些信息,请参见PHP文档),因此我真的在问是否存在与这些方法等效的JavaScript?
__get()
__set()
不用说,理想情况下,我想要一个跨浏览器兼容的解决方案。
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
在get处理程序函数的参数列表中:
target
original
name
receiver``this
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 = bar
请注意,当我们尝试检索foo尚不存在的消息以及创建它时(而不是之后创建)时,如何获取“不存在”消息。
foo
2011年的答案 (请参见上面的2013年和2015年更新) :
不,JavaScript不具有全部属性功能。规范的第11.1.5节介绍了您使用的访问器语法,并且不提供任何通配符或类似的内容。
当然,您可以实现一个函数来执行此操作,但是我猜您可能不想使用f = obj.prop("foo");而不是f = obj.foo;和(obj.prop("foo", value);而不是)obj.foo = value;(该函数必须使用该函数来处理未知属性)。
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... };
但是再次,我无法想象您真的想这样做,因为它如何改变您使用对象的方式。