EcmaScript Object.observer未通知属性更改

时间:2016-06-06 01:45:03

标签: proxy ecmascript-6 observer-pattern

我使用Object.observer使用ES6课程加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时,更改{ {1}}以及将foo.valuefoo.status更改为RUNNING

但是,这是我在运行READY时的结果(在Chrome控制台中):

bar()

undefined是从> 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()中的变化,而不是foo.value。 如果我更改foo.status值"手动"观察到:

foo.status

我可以说,当在类中更改属性类时,它不会通知其观察者。但是,观察到了> 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)} 方法的foo.value更改。

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

谢谢,

Rafael Afonso

更新 - 06/06

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

bar()

当我跑步时,我得到了这个:

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执行之后,通知了两个属性更改。

我在想是否更好地使用Java中的ObservableObserver等方法。有人知道一些以这种方式实现的JS库吗?

更新 - 06/06(2)

根据建议,我尝试使用代理:

foo.status

当我跑步时,我得到了这个:

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);

事实上,这正是我所寻求的。虽然Object.observer目标拦截了目标中的所有类型的变化,但我只对属性设置感兴趣。

1 个答案:

答案 0 :(得分:1)

快速浏览该回购suggests,每帧只执行一次更新(在具有此类概念的环境中)或每17ms执行一次。

因为JavaScript是单线程的,所以如果你改变一个属性,然后在一个不间断的函数(即不是生成器等)中将其更改回来,那么这个包将无法观察到它。

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