为什么Object.observe()不提供更改回调的数据路径?

CoD*_*anX 1 javascript observers ecmascript-harmony object.observe

Object.observe()回调的changes数组包含具有以下四个属性的对象:

  • 名称
  • 宾语
  • 类型
  • 属性oldValue

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe#Parameters

为什么没有path本地提供的?例:

var ob = {
    foo: [
        {moo: "bar", val: 5},
        {val: 8}
    ]
}

ob.foo[0].val = 1;
// callback should provide path "foo.0.val" or "foo[0].val"
Run Code Online (Sandbox Code Playgroud)

有一个Node.js模块扩展Object.observe()到也包括路径:observed.js,
但我担心本机的性能提升observe()会丢失(如果没有,请你解释它是如何实现的?).这也许可以browserify模块,但无法想象它会在同步环境表现良好,我仍然不知道为什么没有人似乎已经想到了一个额外的path属性.

小智 6

因为没有明确的路径.

考虑以下:

var movall = {moo: "bar", val: 5};
var ob1    = {a: mooval};
var ob2    = {b: movall};
Run Code Online (Sandbox Code Playgroud)

现在让我说我观察movall.然后我更新moo.路径是什么?是movall.moo,或ob1.a.moo,或ob2.b.moo?如果我观察到ob1,则没有报告任何变化,因为它的任何属性都没有变化(变化是其中一个属性的内部变量,不计算在内).

对象独立于嵌套在其他对象中的存在.它们可以嵌套在多个其他对象中.没有唯一的"路径"描述如何从可能的多个起点到可能已更改的特定属性.

JS也不知道您到达要更改的财产的路径.因此ob.foo[0].val = 1;,JS只是评估链,到达foo[0]对象,更改其val属性,并且在那时不知道它是如何发生的foo[0].它只知道foo[0]已经改变了.它在内部发生了变化ob,但也可能在其他碰巧具有foo[0]属性的对象中发生了变化.

但是,您可以通过在低级观察/通知机制之上构建一些机器来实现您似乎尝试的目标.我们将在一个对象上定义一个函数,该函数在其属性对象上设置观察者,依此递归,并使用正确构造的路径传播更改记录:

function notifySubobjectChanges(object) {
  var notifier = Object.getNotifier(object);        // get notifier for this object
  for (var k in object) {                           // loop over its properties
    var prop = object[k];                           // get property value
    if (!prop || typeof prop !== 'object') break;   // skip over non-objects
    Object.observe(prop, function(changes) {        // observe the property value
      changes.forEach(function(change) {            // and for each change
        notifier.notify({                           // notify parent object
          object: change.object,                    // with a modified changerec
          name: change.name,                        // which is basically the same
          type: change.type, 
          oldValue: change.oldValue, 
          path: k + 
            (change.path ? '.' + change.path : '')  // but has an addt'l path property
        });
      });
    });
    notifySubobjectChanges(prop);                   // repeat for sub-subproperties
  }
}
Run Code Online (Sandbox Code Playgroud)

(注意:change对象被冻结,我们无法添加任何内容,因此我们必须复制它.)

现在

a = { a: { b: {c: 1 } } };                     // nested objects
notifySubobjectChanges(a);                     // set up recursive observers
Object.observe(a, console.log.bind(console));  // log changes to console
a.a.b.c = 99;

>> 0: Object
  name: "c"
  object: Object
  oldValue: 1
  path: "a.b"                                  // <=== here is your path!
  type: "update"
Run Code Online (Sandbox Code Playgroud)

以上代码不是生产质量,使用风险自负.

  • 如果我理解你正确评论,那么没有额外的机制,对'ob2.movall.moo`的改变不是**改为'ob2`.仅在包含该属性的对象上报告更改.对'ob2.movall.moo`的更改不是**对'ob2`的任何属性的更改,它是对其中一个属性值的**内部**的更改. (2认同)