EcmaScript Object.observer 未通知 属性 更改

EcmaScript Object.observer is not notifying property changes

我正在使用 ES6 classes 加上 Object.observer, using the MaxArt2501 implementation。我有以下代码:

const READY = Symbol("Ready");
const RUNNING = Symbol("Running");

class Foo {

    constructor() {
        this.value = 1;
        this.status = READY;
    }

    bar() {
        this.status = RUNNING;  
        console.log("bar", this.status );
        this.value = this.value + 10;
        this.status = READY;
        console.log("bar", this.status );
    }

}

let foo = new Foo();

Object.observe(foo, function(changes) {
    changes.forEach(function(change) {
        console.log("foo: ", change);
    });
});

我的预期是,当我执行bar()方法时,观察者函数将被调用3次:当将foo.statusREADY更改为RUNNING时,当更改 foo.value 以及将 foo.statusRUNNING 更改为 READY.

但是,这是我在 运行ning bar() 时得到的(在 Chrome 控制台中):

> foo
Foo {value: 1, status: Symbol(Ready)}
> foo.bar()
bar Symbol(Running)
bar Symbol(Ready)
undefined
foo:  Object {name: "value", type: "update", object: Foo, oldValue: 1}
> foo
Foo {value: 11, status: Symbol(Ready)}  

未定义的是bar()方法中的return。但无论如何,看起来只是 foo.value 的变化被真正观察到了,而不是 foo.status。 如果我更改 foo.status 值 "manually",则会观察到:

> foo.status = RUNNING
Symbol(Running)
foo:  Object {name: "status", type: "update", object: Foo, oldValue: Symbol(Ready)}
> foo
Foo {value: 11, status: Symbol(Running)}
> foo.status = READY
Symbol(Ready)
foo:  Object {name: "status", type: "update", object: Foo, oldValue: Symbol(Running)}
> foo
Foo {value: 11, status: Symbol(Ready)}

我可以说,当 属性 class 在 class 内部发生变化时,它不会通知它的观察者。但是,观察到 bar() 方法中的 foo.value 变化。

有人知道这里发生了什么吗?

谢谢,

拉斐尔·阿方索

更新 - 06/06

我做了一个解决方法,虽然不是很优雅,但我可以在我的实际实现中用作基础:

const READY = Symbol("Ready");
const RUNNING = Symbol("Running");

class Foo {

    constructor() {
        this.value = 1;
        this.status = READY;
    }

    bar() {
//      this.status = RUNNING;  
        console.log("bar", this.status );
        this.value = this.value + 10;
//      this.status = READY;
        console.log("bar", this.status );
    }

}

let foo = new Foo();

Object.observe(foo, function(changes) {
    changes.forEach(function(change) {
        if(change.name === 'value') {
            change.object.status = RUNNING;
        }
        console.log("foo: ", change);
    });
});

当我 运行 时,我得到了这个:

> foo.bar()
bar Symbol(Ready)
bar Symbol(Ready)
undefined
foo:  Object {name: "value", type: "update", object: Foo, oldValue: 1}
foo:  Object {name: "status", type: "update", object: Foo, oldValue: Symbol(Ready)}

如您所见,我更改了 foo.status in observable 方法。但是,显然在 foo 执行之后,两个属性更改都会收到通知。

我在想,如果使用 Java 中的 Observable and Observer 这样的方法会不会更好。有人知道以这种方式实现的一些 JS 库吗?

更新 - 06/06 (2)

按照建议,我尝试使用代理:

const READY = Symbol("Ready");
const RUNNING = Symbol("Running");

class Foo {

    constructor() {
        this.value = 1;
        this.status = READY;
    }

    bar() {
        this.status = RUNNING;  
        // console.log("bar", this.status );
        this.value = this.value + 10;
        this.status = READY;
        // console.log("bar", this.status );
    }

}

let observer = {
    set: function(obj, prop, value) {
        let oldValue = obj[prop];
        let result = Reflect.set(obj, prop, value);
        console.log(prop + ": " + oldValue.toString() + " -> " + value.toString());
        return result;
    }
}

let foo = new Proxy(new Foo(), observer);

当我 运行ned 时,我得到了这个:

> foo.bar()
status: Symbol(Ready) -> Symbol(Running)
value: 1 -> 11
status: Symbol(Running) -> Symbol(Ready)
undefined
> foo.bar()
status: Symbol(Ready) -> Symbol(Running)
value: 11 -> 21
status: Symbol(Running) -> Symbol(Ready)
undefined

的确,这就是我要找的。虽然 Object.observer 目标是拦截目标中的各种变化,但我只对属性设置感兴趣。

快速浏览一下该存储库 suggests 每帧仅执行一次更新(在具有此类概念的环境中)或每 17 毫秒执行一次。

因为 JavaScript 是单线程的,如果您更改 属性 然后在单个不间断函数(即不是生成器等)中将其更改回来,它将不会被观察到这个包。

请记住,Object.observe 不再有望成为该语言的一部分。拟议规范的实际实现可能会为您提供每个事件的通知,但不可能针对这种特定情况进行伪造(至少在不将每个对象包装在代理中的情况下)。