【问题标题】:How can I lazy evaluate fields on a javascript object?如何延迟评估 javascript 对象上的字段?
【发布时间】:2014-06-26 15:42:39
【问题描述】:

我想知道是否可以执行以下操作:

var obj = {
   counter: (function(){
                if(!this.val){ this.val = 0; }
                this.val += 1;
                return this.val;
            })();
};

console.log(obj.counter); //should output 1
console.log(obj.counter); //should output 2
console.log(obj.counter); //should output 3
...

有没有办法从这样的对象中获取字段,以便每次访问时重新评估函数?

【问题讨论】:

  • 为什么不用函数而不是字段
  • Counter 被定义为 IIFE,因此您对 this 的引用会丢失给 IIFE 本身。因此,每次您拨打 obj.counter 时,this.val 都将是未定义的,因此设置为 0,然后设置为 1。@ksven 击败了我的答案代码,所以我将其作为评论发布。
  • 好的,我可以把实际的计数变量放在其他地方,仍然可以自动递增吗?

标签: javascript lazy-evaluation


【解决方案1】:

你可以使用getter:

var obj = {};
Object.defineProperty(obj,"counter",{
    get: function() {
        this.val = this.val || 0;
        this.val++;
        return this.val;
    }
});

console.log(obj.counter); // 1
console.log(obj.counter); // 2
console.log(obj.counter); // 3

【讨论】:

  • 这很棒,我不知道它存在。谢谢!
【解决方案2】:

如果您的目标平台支持proxies,则可以这样做:

var obj = Proxy.create({
    get: function(target, value) {
        if(value == 'counter')
            return this.val = (this.val || 0) + 1;
    }
});

console.log(obj.counter); //should output 1
console.log(obj.counter); //should output 2
console.log(obj.counter); //should output 3

另一种选择是吸气剂:

obj = Object.create({}, {
    counter: {
        get: function() {
            return this.val = (this.val || 0) + 1;
        }
    }
})

valueOf 对象(这不适用于console.log,但适用于算术):

var obj = {
    counter: {
        valueOf: function() {
            return this.val = (this.val || 0) + 1;
        }
    }
};

console.log(obj.counter+5); // 6
console.log(obj.counter+5); // 7
console.log(obj.counter+5); // 8

【讨论】:

    【解决方案3】:

    使用Proxy 类和用例来评估属性评估的要求

    /* https://github.com/hack2root/lazyeval */
    
    let lazy = (eval) => ((data) => new Proxy(data, {
      set(obj, key, val) {
      obj[key] = val;
      eval(obj);
      }
    }))({});
    
    // 1. ARRANGE
    let a = 1;
    let b = 2;
    let c;
    
    // 2. ACT
    let func = lazy((f) => {
      if (f.a && f.b) { 
        c = f.a + f.b 
      }
    });
    
    func.a = a;
    func.b = b;
    
    // 3. ASSERT
    console.log("c is", c);
    
    let lazy_require = (requre) => (eval) =>  ((data) => new Proxy(data, {
        set(obj, key, val) {
            obj[key] = val;
            if (requre(obj)) {
                eval(obj);
            }
        }
    }))({});
    
    // 1. ARRANGE
    let a_f = 1;
    let b_f = 2;
    let c_f;
    
    // 2. ACT
    let func_reqire = lazy_require((f) => f.a && f.b);
    
    let lazy_func = func_reqire((f) => {
      c_f = f.a + f.b
    });
    
    lazy_func.a = a_f;
    lazy_func.b = b_f;
    
    // 3. ASSERT
    console.log('c_f is', c_f);
    
    let lazy_require_data = (requre) => (eval) => (data) => new Proxy(data, {
      set(obj, key, val) {
        obj[key] = val;
        if (requre(obj)) {
          eval(obj);
        }
      }
    });
    
    // 1. ARRANGE
    let a_data = 1;
    let b_data = 2;
    let c_data;
    
    // 2. ACT
    let func_require_data = lazy_require_data((f) => f.a && f.b);
    
    let func_data = func_require_data((f) => {
        c_data = f.a + f.b
    });
    
    let func_json = func_data({
        a: a_data,
        b: b_data
    });
    
    func_json.a = a;
    func_json.b = b;
    
    // 3. ASSERT
    console.log('c_data is', c_data);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多