14

是否可以在不使用Proxyand的情况下监听属性变化setInterval

对于普通对象,您可以使用下面的函数,但它适用于所有现有属性,但不适用于包装后可能添加的任何属性。

function wrap(obj) {
  var target = {};
  Object.keys(obj).forEach(function(key) {
    target[key] = obj[key];
    Object.defineProperty(obj, key, {
      get: function() {
        console.log("Get");
        return target[key];
      },
      set: function(newValue) {
        console.log("Set");
        target[key] = newValue;
      }
    });
  });
}

var obj = {
  a: 2,
  b: 3
};
wrap(obj);

obj.a; // Get
obj.a = 2; // Set
obj.b; // Get
obj.b = 2; // Set
obj.c = 2; // Nothing
obj.c; // Nothing

如果对象是一个数组,您还可以侦听该length属性并在它更改时重置所有getset函数。这显然不是很有效,因为它会在添加或删除元素时更改每个元素的属性。

所以我认为这不是Object.defineProperty答案。

我不想使用的原因setInterval是因为间隔大会使包装不可靠,而间隔小会对效率产生很大影响。

4

1 回答 1

5

遗憾的是,不,这就是代理如此重要的原因。目前,除了 Proxy 之外,没有其他方法可以在将属性添加到对象时触发代码。

正如您所说,您可以使用Object.definePropertyvar a = { get x() {...}, set x(value) {...} }不检测新属性。


大多数框架依赖于脏检查:在给定时间比较对象。时间是主要区别所在。

AngularJS (Angular 1.x) 为您提供了用于异步操作的特殊功能,例如$timeout$http它以自己的方式监听 DOM 事件,这些事件将包装您的回调并在您的代码之后运行检查。

Angular(Angular 2 到 N)使用Zone.js为您的代码创建“运行上下文”,任何异步回调都会被 Zone.js 拦截。它与 AngularJS 的解决方案基本相同,但可以自动运行。

React 做了类似的事情,但它不是跟踪你的变量,而是运行渲染器并比较生成的 DOM(虚拟 DOM)是否不同。

于 2019-06-06T10:32:29.977 回答