【问题标题】:How to use MutationObserver with an Object?如何将 MutationObserver 与对象一起使用?
【发布时间】:2020-01-28 09:46:21
【问题描述】:

我有以下对象:

mind = {
    queries: [],
    actions: []
};

我根据另一个函数更新queriesactions

我想检测它们每次更新和更改的时间,我听说过MutationObserver,所以我尝试调用它:

var muob = (window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver);
var ob = new muob(function(m) {
    console.log('It works!');
});
ob.observe(mind, { subtree: true });

但它不起作用。我得到回报:

未捕获的类型错误:无法在“MutationObserver”上执行“观察”:参数 1 不是“节点”类型。

我的代码有什么问题?

【问题讨论】:

标签: javascript


【解决方案1】:

MutationObserver 仅适用于 DOM 元素,不适用于对象:

var ob = new MutationObserver(function(m) {
    console.log('It works!');
});
ob.observe(mind, { childList: true });

mind.textContent = 'foo';
<div id="mind"></div>

对于您正在做的事情,您可以使 queriesactions 属性具有更新数组的方法,例如:

const mind = {
  _queries: [],
  _actions: [],
  queries: {
    push(...args) {
      console.log('Push detected');
      mind._queries.push(...args);
    },
    get() {
      return mind._queries;
    }
  },
  actions: {
    push(...args) {
      console.log('Push detected');
      mind._actions.push(...args);
    },
    get() {
      return mind._actions;
    }
  }
};

mind.queries.push('foo');
console.log(mind.queries.get());

或者,使用代理:

const handler = {
  set(obj, prop, newVal) {
    console.log('Change detected');
    return obj[prop] = newVal;
  },
  get(obj, prop) {
    return obj[prop];
  }
};

const mind = {
  queries: new Proxy([], handler),
  actions: new Proxy([], handler),
};

mind.queries.push('foo');
console.log(mind.queries);

(上面的 sn-p 记录了两次Change detected,因为它必须更新数组上的0 属性更改数组的.length

不过,这还是很奇怪 - 如果在代码中更改数组的位置,您还调用另一个函数(It works! 部分)来指示发生了更新,那将更加优雅。

【讨论】:

  • 使用这些get 方法,您将需要一个代理。否则,可以直接修改,无需通知。
  • 您好,感谢您的帮助。我可以在回调函数中的变量上使用console.log() 吗?例如:Mutation...(function(variable) { console.log(variable); }); ?
  • @user11247237 setter 和 getter 是函数,因此您可以根据需要记录它们的参数。例如console.log('newVal', newVal);
【解决方案2】:

MutationObserver 用于 DOM 元素,而不是 JavaScript 对象。

JavaScript 对象没有等价物¹,但您可以结合使用 Proxy 对象和访问器属性来获取对这些数组进行任何更改的通知。您将使用代理了解数组何时被修改,并通过创建xy 访问器属性,您可以知道它们何时被更改(并以此为机会将它们包装在代理中)。

这是一个粗略的草图:

const mind = (() => {
    function wrap(array) {
        return new Proxy(array, {
            set(target, propName, value, receiver) {
                beforeChange(target, propName, value, receiver);
                const result = Reflect.set(target, propName, value);
                afterChange(target, propName, value, receiver);
                return result;
            }
            // ...you may want other traps here...
        });
    }

    function beforeChange(target, name, value, receiver) {
        console.log("beforeChange", name, value);
    }

    function afterChange(target, name, value, receiver) {
        console.log("afterChange", name, value);
    }

    let queries = wrap([]);
    let actions = wrap([]);
    return {
        get queries() {
            return queries;
        },
        set queries(value) {
            beforeChange(queries, "*queries*", value);
            queries = wrap(value);
            afterChange(queries, "*queries*", value);
        },
        get actions() {
            return queries;
        },
        set queries(value) {
            beforeChange(queries, "*actions*", value);
            queries = wrap(value);
            afterChange(queries, "*actions*", value);
        }
    };
})();

mind.queries.push(1);
mind.actions.push("two");
console.log(mind.actions);
mind.actions[0] = "TWO";
console.log(mind.actions);
mind.queries = [];
mind.queries[10] = "ten";
console.log(mind.queries);
.as-console-wrapper {
    max-height: 100% !important;
 }

¹ 在很短的时间内会有 Object.observe,但它被放弃了,取而代之的是 Proxy。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 2021-06-25
    • 2018-02-07
    • 2020-09-24
    相关资源
    最近更新 更多