我想为这个我也问自己的问题提供一个明确的答案,所以我查看了Object.observe 规范。
以下是您需要了解的内容Object.getNotifier(obj).performChange(changeType, changeFn)
:
- 它运行
changeFn
- 在
changeFn
运行时,它故意不通知任何观察者可能发生在属性上的更改obj
- 您可以
changeFn
返回一个对象:obj
的观察者将收到该对象自己的属性的通知
亲自查看,%NotifierPrototype%.performChange(changeType, changeFn)
是您在规范中寻找的内容。
应用于您的示例,这意味着这两个导致完全相同的结果,但做事略有不同:
示例 1:
increment: function(amount) {
var notifier = Object.getNotifier(this);
notifier.performChange(Thingy.INCREMENT, function() {
this.a += amount;
this.b += amount;
});
notifier.notify({
object: this,
type: Thingy.INCREMENT,
incremented: amount
});
}
在第一个示例中:
- 根据
performChange()
的行为,回调函数内对对象属性的更改将保持沉默
- 由于回调函数返回
undefined
,performChange()
不会通知任何观察者其他任何事情
- 但是,最后调用
notify()
显式通知适当的观察者,并传递了更改记录
示例 2:
increment: function(amount) {
var notifier = Object.getNotifier(this);
notifier.performChange(Thingy.INCREMENT, function() {
this.a += amount;
this.b += amount;
return { incremented: amount };
});
}
在第二个示例中:
- 根据
performChange()
的行为,回调函数内对对象属性的更改将保持沉默
- 由于回调函数返回一个对象,因此将通知适当的观察者一个与示例 1 中
performChange()
显式调用所产生的对象相同的对象:notify()
{ object: Object, type: Thingy.INCREMENT, increment: amount }
这两个示例应该涵盖您想要使用的大多数情况performChange()
,以及如何使用它。不过我会继续潜水,因为这只野兽的行为很有趣。
异步性
观察者是异步执行的。这意味着increment()
上面示例中函数内部发生的所有事情实际上都会在执行完毕后报告increment()
给观察者——而且只有到那时。
换句话说,所有这些:
- 对观察对象的属性进行更改
performChange()
performChange()
在的回调中返回一个对象
- 打电话
notify()
increment()
只有在完成运行后才会通知适当的观察者。
同步变更交付
如果您需要了解increment()
执行期间的待处理更改(待处理更改 = 将在 结束时报告给观察者increment()
但尚未报告的所有更改),有一个解决方案:Object.deliverChangeRecords(callback)
.
请注意,尽管这callback
需要引用您之前已经注册为该对象的观察回调的函数。
换句话说,这是行不通的:
(function() {
var obj = { prop: "a" };
Object.observe(obj, function(changes) {
console.log(changes);
});
obj.prop = "b";
Object.deliverChangeRecords(function(changes) {
console.log(changes);
});
console.log("End of execution");
})(); // Meh, we're notified of changes here, which isn't what we wanted
虽然这将:
(function() {
var obj = { prop: "a" },
callback = function(changes) {
console.log(changes);
};
Object.observe(obj, callback)
obj.prop = "b";
Object.deliverChangeRecords(callback); // Notified of changes here, synchronously: yay!
console.log("End of execution");
})();
这样做的原因是,在内部,调用Object.observe(obj, callback)
一个对象obj
会将传递的callback
函数添加到的观察回调列表(在规范中obj
称为)。[[ChangeObservers]]
这些回调中的每一个都只会针对特定类型的更改(第三个Object.observe()
参数)执行,如果没有传递参数,则将执行所有默认更改。(这是一个重要的细节,因为这意味着如果您想使用type
更改的自定义,您需要将其显式传递给Object.observe()
的第三个参数,否则您将不会收到有关该类型的任何更改的通知。)
此外,每个待处理的更改都将在内部添加到每个匹配的观察回调队列中。这意味着每个观察回调都有自己的一组未决更改。
这正是Object.deliverChangeRecords(callback)
它的用途:它接受所有待处理的更改callback
并通过传递所有这些更改来执行该回调。
这就解释了为什么deliverChangeRecords()
只需要一个参数,即回调的参数。如下例所示,将回调传递给deliverChangeRecords()
将执行该回调及其所有未决更改,包括来自多个对象的更改。这符合回调的一般行为,可能是异步调用,也可能是通过deliverChangeRecords()
.
(function() {
var obj1 = { prop1: "a" },
obj2 = { prop2: "a" },
commonCallback = function(changes) {
console.log(changes);
};
Object.observe(obj1, commonCallback);
Object.observe(obj2, commonCallback);
obj1.prop1 = "b";
obj2.prop2 = "b";
Object.deliverChangeRecords(commonCallback); // Notified of the changes to both obj1.prop1 and obj2.prop2
})();
此外,规范中提供了很好的 使用示例。