【问题标题】:Proxy substitue for ES5ES5 的代理替代品
【发布时间】:2019-03-26 14:52:19
【问题描述】:

是否可以不使用ProxysetInterval 来监听属性变化?

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

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 的原因是因为间隔大会使包装不可靠,而间隔小会对效率产生很大影响。

【问题讨论】:

  • 不,你不能在 ES5 中这样做。
  • @Bergi 像 Angular 这样的单页应用程序是如何做到的? setInterval?
  • 过去?是的,我想是的,超时或显式触发脏检查。
  • 您基本上需要使用angular提供的$http,它包装了http调用以在最后进行摘要。他们还有一个$timeout$intervalsetTimeoutsetInterval 类似。当你创建这样一个框架时,你需要使用框架中提供的所有方法,或者你可以调用$scope.$digest()手动触发摘要,如果你做了“角度”之外的事情
  • Angularjs 遵循称为dirty check 的东西,它基本上是从rootScope 到所有子作用域的watchers 列表迭代,并比较scope 值是否已更改。这在后台不断发生,每次运行都称为digest cycle。它们的内部结构可能会变得非常复杂,因此始终建议使用它们的包装方法(例如:$timeout instead of setTimeout

标签: javascript object ecmascript-5 es5-compatiblity


【解决方案1】:

很遗憾,不,这就是代理如此重要的原因。目前,除了 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)是否不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    相关资源
    最近更新 更多