2016-06-06 3 views
0

Я использую классы ES6 плюс Object.observer, используя MaxArt2501 implementation. У меня есть этот код ниже:EcmaScript Object.observer не уведомляет об изменениях свойств

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.status от READY к RUNNING, при изменении foo.value и при изменении foo.status от RUNNING до READY.

Однако, это то, что я получил при запуске 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() метода. Но так или иначе, похоже, что только изменение в 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 в методе bar().

Кто-нибудь имеет представление о том, что здесь происходит?

Спасибо,

Рафаэль Afonso

ОБНОВЛЕНИЕ - 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 на наблюдаемый метод. Однако, по-видимому, сразу после выполнения foo оба изменения свойств уведомляются.

Я думал, если бы не было лучше использовать такой подход, как Observable и Observer в Java. Кто-нибудь знает какую-то библиотеку JS, которая реализует таким образом?

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

Когда я переехала машина, я получил это:

> 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 перехватывают все виды изменений в цели, меня интересует только настройка свойств.

+0

FYI 'Object.observe' был удален из спецификации ES6. Это устарело. – naomik

+0

Я знаю, но я включил этот полипол для удовлетворения моих потребностей. –

ответ

1

Быстрое снятие этого репо suggests, что обновления выполняются только один раз за кадр (в средах с таким понятием) или один раз каждые 17 мс.

Поскольку JavaScript является однопоточным, если вы изменяете свойство и затем изменяете его обратно в рамках одной непрерывной функции (т. Е. Нет генератора и т. Д.), То этот пакет не будет наблюдаться.

Имейте в виду, что Object.observe больше не находится на пути, чтобы стать частью языка. Фактическая реализация предлагаемой спецификации могла бы дать вам уведомления для каждого события, но это невозможно подделать для этой конкретной ситуации (по крайней мере, без упаковки каждого объекта в прокси).

Смежные вопросы