是否可以在JavaScript中实现动态getter / setter? [英] Is it possible to implement dynamic getters/setters in JavaScript?

查看:185
本文介绍了是否可以在JavaScript中实现动态getter / setter?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何为名字已经知道的属性创建getter和setter,通过这样做:

I am aware of how to create getters and setters for properties whose names one already knows, by doing something like this:

// 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。

Now, my question is, is it possible to define sort of catch-all getters and setters like these? I.e., create getters and setters for any property name which isn't already defined.

使用<$ c在PHP中可以实现这个概念$ c> __ get()和 __ set()魔术方法(参见 PHP文档以获取有关这些的信息),所以我真的要问是否有相当于这些的JavaScript?

The concept is possible in PHP using the __get() and __set() magic methods (see the PHP documentation for information on these), so I'm really asking is there a JavaScript equivalent to these?

毋庸置疑,我非常喜欢跨浏览器兼容的解决方案。

Needless to say, I'd ideally like a solution that is cross-browser compatible.

推荐答案

2013年和2015年更新 (请参阅以下2011年的原始答案)

此更改为ES2015(又名ES6)规范:JavaScript现在有 代理 。代理允许您创建对象(外观)其他对象的真实代理。这是一个简单的示例,它将任何字符串的属性值转换为检索的所有上限:

This changed as of the ES2015 (aka "ES6") specification: JavaScript now has proxies. Proxies let you create objects that are true proxies for (facades on) other objects. Here's a simple example that turns any property values that are strings to all caps on retrieval:

"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"

你要做的操作t override具有默认行为。在上面,我们覆盖的只是 get ,但是你可以勾选一整套操作。

Operations you don't override have their default behavior. In the above, all we override is get, but there's a whole list of operations you can hook into.

get 处理函数的参数列表中:

In the get handler function's arguments list:


  • target 是被代理的对象(在我们的例子中是原始)。

  • name (当然)是要检索的属性的名称,通常是字符串,但也可以是符号。

  • 如果属性是访问者而不是数据属性,接收器是getter函数中应该用作 this 的对象。在正常情况下,这是代理或继承自它的东西,但它可以是任何东西,因为陷阱可能由 Reflect.get 触发。

  • target is the object being proxied (original, in our case).
  • name is (of course) the name of the property being retrieved, which is usually a string but could also be a Symbol.
  • receiver is the object that should be used as this in the getter function if the property is an accessor rather than a data property. In the normal case this is the proxy or something that inherits from it, but it can be anything since the trap may be triggered by Reflect.get.

这可以让你创建一个具有你想要的全能getter和setter功能的对象:

This lets you create an object with the catch-all getter and setter feature you want:

"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}`);

上面的输出是:

Getting non-existent property 'foo'
[before] obj.foo = undefined
Setting non-existent property 'foo', initial value: bar
[after] obj.foo = bar

注意我们在尝试检索时如何获取不存在的消息 foo 当它还不存在时,我们再创建它时,但不是在那之后。

Note how we get the "non-existent" message when we try to retrieve foo when it doesn't yet exist, and again when we create it, but not after that.

2011年回答 (见上文2013和2015年更新)

不,JavaScript没有全面的属性功能。您正在使用的访问器语法包含在规范的第11.1.5节中,并且没有提供任何通配符或类似的东西。

No, JavaScript doesn't have a catch-all property feature. The accessor syntax you're using is covered in Section 11.1.5 of the spec, and doesn't offer any wildcard or something like that.

当然,你可以实现一个功能,但我猜你可能不想要使用 f = obj.prop(foo); 而不是 f = obj.foo; obj.prop(foo,value); 而不是 obj.foo = value; (这对于用于处理未知属性的函数。)

You could, of course, implement a function to do it, but I'm guessing you probably don't want to use f = obj.prop("foo"); rather than f = obj.foo; and obj.prop("foo", value); rather than obj.foo = value; (which would be necessary for the function to handle unknown properties).

FWIW,getter函数(我没有打扰setter逻辑)看起来像这样:

FWIW, the getter function (I didn't bother with setter logic) would look something like this:

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...
};

但是再一次,我无法想象你真的想要那样做,因为它是怎么回事改变你使用对象的方式。

But again, I can't imagine you'd really want to do that, because of how it changes how you use the object.

这篇关于是否可以在JavaScript中实现动态getter / setter?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆