运行 设置深度 属性 时的函数

Run a function when deep property is set

我有一个像

这样的对象
const obj = { field1: obj1, field2: obj2 }

现在我想 运行 当 obj 中的任何内容发生更改时的函数:

function objChanged() { ... }

// decorate obj somehow ...

obj.field3 = data; // objChanged should be called (Proxy can see it)
obj.field1.val = data; //objChanged should be called (Proxy can't see it?)

据我所知,有一个 MutationObserver which works only for DOM and Proxy 只拦截自己的属性,对吧?

我不拥有 obj1 所以我无法更改它。有没有办法实现这个功能?

下面的代码片段将监听对象 属性 您可以遍历对象属性以监听所有对象。我很好奇,你想达到什么目的?

const dog = { bark: true };

function Observer(o, property) {
  var _this = this;
  this.observers = [];

  this.Observe = function (notifyCallback) {
    _this.observers.push(notifyCallback);
  };

  Object.defineProperty(o, property, {
    set: function (val) {
      _this.value = val;
      for (var i = 0; i < _this.observers.length; i++) {
        _this.observers[i](val);
      }
    },
    get: function () {
      return _this.value;
    },
  });
}

const observer = new Observer(dog, "bark");

observer.Observe(function (value) {
  l("Barked");
});

dog.bark = true;
dog.bark = true;
dog.bark = true;
dog.bark = true;

Orgil 的答案仅适用于需要知道和编码的单个 属性。我想要一个适用于所有属性的解决方案,包括后来添加的。受他创建观察对象的想法的启发,我创建了一个动态代理,可以在需要时添加另一个代理。

在以下代码中,dog1 用作代理:设置其属性会修改原始 dog 对象并将分配的值记录到控制台。

function AssignProxy(o, fn, path) {
    var tree = {};
    if(!path) path = "obj";
    return new Proxy(o, {
        get: (_, prop) => {
            if(typeof o[prop] != "object") return o[prop];
            if(tree[prop] === undefined) tree[prop] = AssignProxy(o[prop], fn, `${path}.${prop}`);
            return tree[prop];
        },
        set: (_, prop, val) => fn(o[prop] = val, prop, o, path) || 1
    });
}


/****** TEST *******/

const dog = {
    sounds: {},
    name: "Spike"
};

let callback = (val, prop, o, path) => console.log(`assigning ${path}.${prop} to ${val}`)
const dog1 = AssignProxy(dog, callback, "dog1");

dog1.name = "Tyke"; // overwrite property
dog1.age = 4; // create a property
dog1.sounds.howl = "hoooooowl"; // create a deep property
dog1.sounds.howl = {text: "hoowl", pitch: 5000}; // overwrite the deep property
var howl = dog1.sounds.howl; // access by reference
howl.pitch = 6000; // overwrite later added property
console.log(dog); // verify the original object