简体   繁体   English

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

[英]Why does Object.observe() not provide the data path of change to a callback?

The changes array of an Object.observe() callback contains objects with the following four properties: Object.observe()回调的changes数组包含具有以下四个属性的对象:

  • name 名称
  • object 宾语
  • type 类型
  • oldValue 旧值

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

Why isn't there a path provided natively? 为什么没有本地提供的path Example: 例:

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"

There's a Node.js module that extends Object.observe() to also include the path: observed.js , 有这么延伸的Node.js模块Object.observe()也包括路径: observed.js
but I worry the performance gain of a native observe() will be lost (if no, could you please explain how it is implemented then?). 但是我担心本机的observe()的性能提升会丢失(如果没有,您能解释一下它是如何实现的吗?)。 It might be possible to browserify the module, but can't imagine it will perform well in a synchronous environment and I still wonder why nobody seems to have thought about an additional path property. 这也许可以browserify模块,但无法想象它会在同步环境表现良好,我仍然不知道为什么没有人似乎已经想到了一个额外的path属性。

Because there is no clear path. 因为没有明确的道路。

Consider the following: 考虑以下:

var movall = {moo: "bar", val: 5};
var ob1    = {a: mooval};
var ob2    = {b: movall};

Now let's say I observe movall . 现在假设我观察了movall Then I update moo . 然后我更新moo What is the path? 路径是什么? Is it movall.moo , or ob1.a.moo , or ob2.b.moo ? movall.moo还是ob1.a.mooob2.b.moo If I observe ob1 , there is no change reported, since there is no change to any of its properties (the change was internal to one of its properties, which doesn't count). 如果我观察到ob1 ,则没有报告更改,因为它的任何属性都没有更改(更改是其中一个属性的内部更改,不计在内)。

Objects are independent of their existence nested within other objects. 对象与其嵌套在其他对象中的存在无关。 They can be nested within multiple other objects. 它们可以嵌套在多个其他对象中。 There is no unique "path" that describes how to get from potentially multiple starting points down to a specific property which may have changed. 没有唯一的“路径”描述如何从可能的多个起点下降到可能已更改的特定属性。

Nor does JS know the path by which you reached the property being changed. JS也不知道您到达要更改的属性的路径。 So in ob.foo[0].val = 1; 因此在ob.foo[0].val = 1; , JS simply evaluates the chain, arrives at the foo[0] object, changes its val property, and at that point has no idea how it happened to arrive at foo[0] . ,JS只是简单地评估链,到达foo[0]对象,更改其val属性,到那时还不知道它是如何到达foo[0] All it knows is that foo[0] has changed. 它所知道的只是foo[0]已更改。 It changed within ob , but it might also have changed within some other object that happens to have foo[0] as a property. 它在ob内已更改,但在其他一些恰好具有foo[0]作为属性的对象中也可能已更改。

However, you can possibly achieve what you seem to be trying to by building some machinery on top of the low-level observe/notify mechanism. 但是,您可以通过在底层观察/通知机制之上构建一些机制来实现您似乎想要的目标。 We shall define a function on an object which sets up observers on its property objects, and so on recursively, and propagates change records back up with properly constructed paths: 我们将在对象上定义一个函数,该函数在其属性对象上设置观察者,依此类推,并通过适当构造的路径将更改记录传播回:

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
  }
}

(Note: the change object is frozen and we cannot add anything to it, so we have to copy it.) (注意: change对象是冻结的,我们无法向其添加任何内容,因此我们必须将其复制。)

Now 现在

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"

The above code is not production-quality, use at your own risk. 上面的代码不是生产质量的,使用后果自负。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM