代码之家  ›  专栏  ›  技术社区  ›  IsraGab

getter可以从两个不同的源返回数据吗[duplicate]

  •  0
  • IsraGab  · 技术社区  · 7 年前

    我知道如何为已知名称的属性创建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?一、 为任何属性名创建getter和setter 已经定义。

    在PHP中使用 __get() __set() the PHP documentation 关于这些的信息),所以我真的在问是否有一个JavaScript等价于这些?

    不用说,我最理想的解决方案是跨浏览器兼容的。

    0 回复  |  直到 10 年前
        1
  •  215
  •   T.J. Crowder    7 年前

    (2011年的原始答案见下文) :

    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

    得到 处理程序函数的参数列表:

    • target original ,在我们的例子中)。
    • name 是(当然)要检索的属性的名称,它通常是字符串,但也可以是符号。
    • receiver 是应该用作 this 可以 因为陷阱可能是由 Reflect.get

    这使您可以使用所需的catch all 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}`);

    上述输出为:

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

    请注意,当我们尝试检索时,我们是如何获得“不存在”消息的 foo 当它还不存在的时候,当我们创造它的时候,但在那之后。


    2011年的答案 (2013年和2015年更新见上文) :

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

        2
  •  4
  •   clami219 bishop    11 年前

    以下是解决这一问题的原始方法:

    var obj = {
      emptyValue: null,
      get: function(prop){
        if(typeof this[prop] == "undefined")
            return this.emptyValue;
        else
            return this[prop];
      },
      set: function(prop,value){
        this[prop] = value;
      }
    }
    

    //To set a property
    obj.set('myProperty','myValue');
    
    //To get a property
    var myVar = obj.get('myProperty');
    

    编辑: 基于我提出的改进的、更面向对象的方法如下:

    function MyObject() {
        var emptyValue = null;
        var obj = {};
        this.get = function(prop){
            return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
        };
        this.set = function(prop,value){
            obj[prop] = value;
        };
    }
    
    var newObj = new MyObject();
    newObj.set('myProperty','MyValue');
    alert(newObj.get('myProperty'));
    

    你可以看到它在工作 here .

        3
  •  0
  •   Andrew    5 年前

    前言:

    T.J. Crowder's answer 提到一个 Proxy 代理 代理 我将在下面展示给你看。

    代理 最近在firefoxonlinux上进行了彻底的测试,发现它的功能非常强大,但也有点令人困惑/难以使用。更重要的是,我还发现它的速度非常慢(至少就目前JavaScript的优化程度而言),我指的是deca倍数较慢的领域


    要具体实现动态创建的getter和setter,可以使用 Object.defineProperty() Object.defineProperties()

    要点是可以在一个对象上定义getter和/或setter,如下所示:

    let obj = {};
    let val = 0;
    Object.defineProperty(obj, 'prop', { //<- This object is called a "property descriptor".
      //Alternatively, use: `get() {}`
      get: function() {
        return val;
      },
      //Alternatively, use: `set(newValue) {}`
      set: function(newValue) {
        val = newValue;
      }
    });
    
    //Calls the getter function.
    console.log(obj.prop);
    let copy = obj.prop;
    //Etc.
    
    //Calls the setter function.
    obj.prop = 10;
    ++obj.prop;
    //Etc.
    

    • 您不能使用 value 如上所示)与 get 和/或 set

      对象中的属性描述符有两种主要类型:数据描述符和访问器描述符。A 数据描述符 是具有值的属性,该值可能是可写的,也可能是不可写的。安 是由getter-setter对函数描述的属性。描述符必须是这两种风格中的一种;不能同时是这两种风格。

    • val 财产 外部 调用/属性描述符。这是标准行为。
    • 根据误差 here ,不要设置 writable true 如果使用 设置
    • configurable enumerable ,但是,取决于您的目标;从文档:

      可配置

      • 如果只能从该属性的相应属性中删除,则只能从该属性中删除。

      • 默认为false。


      • 是的 当且仅当此属性在枚举相应对象的属性时显示。


    在这一点上,这些也可能是有趣的:

        4
  •  -6
  •   Bruno    12 年前
    var x={}
    var propName = 'value' 
    var get = Function("return this['" + propName + "']")
    var set = Function("newValue", "this['" + propName + "'] = newValue")
    var handler = { 'get': get, 'set': set, enumerable: true, configurable: true }
    Object.defineProperty(x, propName, handler)
    

    这对我有用