【问题标题】:Detecting changes in a Javascript array using the Proxy object使用 Proxy 对象检测 Javascript 数组中的更改
【发布时间】:2016-02-24 18:33:25
【问题描述】:

在 Javascript 中观察数组的变化是相对简单的。

我使用的一种方法是这样的:

// subscribe to add, update, delete, and splice changes
Array.observe(viewHelpFiles, function(changes) {
  // handle changes... in this case, we'll just log them 
  changes.forEach(function(change) {
    console.log(Object.keys(change).reduce(function(p, c) {
      if (c !== "object" && c in change) {
        p.push(c + ": " + JSON.stringify(change[c]));
      }
      return p;
    }, []).join(", "));
  });
});

但是,我最近读到 Array.observe 已被弃用,我们应该使用 proxy object instead.

我们如何检测 Proxy 对象数组的变化?我找不到任何示例,有人有兴趣详细说明吗?

【问题讨论】:

  • 我在 Google 中寻找“代理观察”,得到了这个gist.github.com/ebidel/1b553d571f924da2da06
  • 请注意,代理目前仅在 Firefox 和一些转译器中受支持,您不会在生产代码中使用它。
  • 现在所有主流浏览器都支持代理,除了 Internet Explorer。

标签: javascript


【解决方案1】:

根据我从MDN page 中了解到的信息,您可以创建一个通用处理程序,您可以在其中处理对任何对象的所有更改。

从某种意义上说,你编写了一个拦截器,它会在你每次从数组中获取值或设置值时进行干预。然后,您可以编写自己的逻辑来跟踪更改。

var arrayChangeHandler = {
  get: function(target, property) {
    console.log('getting ' + property + ' for ' + target);
    // property is index in this case
    return target[property];
  },
  set: function(target, property, value, receiver) {
    console.log('setting ' + property + ' for ' + target + ' with value ' + value);
    target[property] = value;
    // you have to return true to accept the changes
    return true;
  }
};

var originalArray = [];
var proxyToArray = new Proxy( originalArray, arrayChangeHandler );

proxyToArray.push('Test');
console.log(proxyToArray[0]);

// pushing to the original array won't go through the proxy methods
originalArray.push('test2');

// the will however contain the same data, 
// as the items get added to the referenced array
console.log('Both proxy and original array have the same content? ' 
  + (proxyToArray.join(',') === originalArray.join(',')));

// expect false here, as strict equality is incorrect
console.log('They strict equal to eachother? ' + (proxyToArray === originalArray));

然后输出:

getting push for 
getting length for 
setting 0 for  with value Test 
setting length for Test with value 1
getting 0 for Test
Test

代理的注意事项是,在对象上定义的所有内容都将被拦截,这可以在使用 push 方法时观察到。

将被代理的原始对象不会发生变异,对原始对象所做的更改不会被代理捕获。

【讨论】:

  • 警告,IE11 不支持。
  • @Chexpir true,根据 MDN,IE 甚至完全不支持它,但它应该被当前的 MS 浏览器 Edge 支持
  • 但是您根本没有观察数组​​,您创建了一个代理,代理将更改转发到数组。问题是如何实际观察数组本身。将代理命名为“arrayToObserve”具有误导性。那些代理和数组是两个完全不同的对象。
  • @Winchestro 是的,您根本没有观察对象,但代理正在为您执行此操作,但是如果您将arrayToObserve 输出,说明正在返回一个数组对象通过您的任何api函数,那有关系吗?最终用户会知道他可以按预期与阵列进行交互。这只是一个命名问题吗? (虽然我必须承认,回顾帖子,我认为我的语言可以做一些小的更新)
  • @Icepickle 如果不想为了观察而用代理替换所有内容,这很重要。假设您有数百万个对象,并且想要一次“观察”其中的 10 个。你是否用代理替换了数百万个,只是为了能够观察其中的任何 10 个?
【解决方案2】:

你可以这样做

new Proxy([], {
    get(target, prop) {
        const val = target[prop];
        if (typeof val === 'function') {
            if (['push', 'unshift'].includes(prop)) {
                return function (el) {
                    console.log('this is a array modification');
                    return Array.prototype[prop].apply(target, arguments);
                }
            }
            if (['pop'].includes(prop)) {
                return function () {
                    const el = Array.prototype[prop].apply(target, arguments);
                    console.log('this is a array modification');
                    return el;
                }
            }
            return val.bind(target);
        }
        return val;
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 2021-11-28
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多