Pergunta

Indo através de documentação Javascript, eu achei as duas funções seguintes em um objeto Javascript parece interessante:

.watch - Relógios para uma propriedade para ser atribuído um valor e executa uma função quando isso ocorre
. .unwatch -. Remove um conjunto watchpoint com o método do relógio

Exemplo de uso:

o = { p: 1 };
o.watch("p", function (id,oldval,newval) {
    console.log("o." + id + " changed from " + oldval + " to " + newval)
    return newval;
});

Sempre que alterar o valor da propriedade de "p", esta função é acionado.

o.p = 2;   //logs: "o.p changed from 1 to 2"

Eu estou trabalhando em Javascript para os últimos anos e nunca usou essas funções.
Alguém por favor pode jogar alguns casos bom uso onde estas funções virá a calhar?

Foi útil?

Solução

O relógio é realmente concebido para a validação dos valores de propriedade. Por exemplo, você pode validar que algo é um inteiro:

obj.watch('count', function(id, oldval, newval) {
    var val = parseInt(newval, 10);
    if(isNaN(val)) return oldval;
    return val;
});

Você poderia usá-lo para comprimento da corda de validação:

obj.watch('name', function(id, oldval, newval) {
    return newval.substr(0, 20);
});

No entanto, estas são apenas disponível nas versões mais recentes do motor SpiderMonkey JavaScript. Great se você estiver usando Jaxer ou incorporando o motor SpiderMonkey, mas não é realmente disponível no seu browser ainda (a menos que você é usando FF3).

Outras dicas

Confira Object.defineProperty Object.prototype.\__defineGetter__ (ou \__defineSetter__) para ver onde esta funcionalidade é rubrica.

Object.defineProperty deve estar disponível em todos os navegadores contemporâneos real logo agora.

Agora é 2018 e as respostas para essa pergunta está um pouco desatualizado:

  • Object.watch e Object.observe são ambos obsoleto e não deve ser usado.
  • onPropertyChange é um evento de elemento DOM manipulador que só funciona em algumas versões do IE.
  • Object.defineProperty permite que você faça uma imutável objeto imóvel, o que lhe permitiria detectar tentativas de mudanças, mas também iria bloquear quaisquer alterações.
  • Defining setters e getters obras , mas requer um monte de código de configuração e ele não funciona bem quando você precisa excluir ou criar novas propriedades.

Hoje, agora você pode usar o Proxy objeto para monitor (e interceptar) as alterações feitas em um objeto. É construído propositadamente para o que o OP está tentando fazer. Aqui está um exemplo básico:

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
      return true;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'

Os únicos inconvenientes do objeto Proxy são:

  1. O objeto Proxy não está disponível em navegadores mais antigos (como IE11) eo polyfill não pode funcionalidade Proxy totalmente replicar.
  2. objetos
  3. proxy nem sempre se comportam como esperado com objetos especiais (por exemplo, Date) -. objeto Proxy é melhor emparelhado com objetos simples ou Arrays

Se você precisa observar alterações feitas em um objeto aninhado , então você precisa usar uma biblioteca, tal especializada como observable Magro (que eu autoria). Funciona assim:

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]

Você poderia dar uma olhada na biblioteca de Eventos Javascript Propery . É um pequeno estendendo Object.defineProperty biblioteca com algumas chamadas de eventos, que fiz recentemente. Ele adiciona algumas propriedades on[event] que podem ser utilizadas como as propriedades on[event] de HTML-Objects. Ele também tem uma verificação de tipo simples, que chama o evento onerror se ele falhar.

Como o código que resultaria em algo como isto:

var o = {}
Object.defineProperty(o, "p", {
    value:1,
    writable:true,
    onchange:function(e){
        console.log("o." + e.target + " changed from " + e.previousValue + " to " + e.returnValue);
    }
})

Você pode usar setInterval

Object.prototype.startWatch = function (onWatch) {

    var self = this;

    if (!self.watchTask) {
        self.oldValues = [];

        for (var propName in self) {
            self.oldValues[propName] = self[propName];
        }


        self.watchTask = setInterval(function () {
            for (var propName in self) {
                var propValue = self[propName];
                if (typeof (propValue) != 'function') {


                    var oldValue = self.oldValues[propName];

                    if (propValue != oldValue) {
                        self.oldValues[propName] = propValue;

                        onWatch({ obj: self, propName: propName, oldValue: oldValue, newValue: propValue });

                    }

                }
            }
        }, 1);
    }



}

var o = { a: 1, b: 2 };

o.startWatch(function (e) {
    console.log("property changed: " + e.propName);
    console.log("old value: " + e.oldValue);
    console.log("new value: " + e.newValue);
});

Object.defineProperty

Promise

remover Promise e manter callback somente se Promessa não é suportado no seu browser alvo

Importante:

1) Esteja ciente de comportamento assíncrono em usar promessa.

2) Object.defineProperty não acionar o retorno de chamada, único operador de atribuição '=' faz

Object.onPropertySet = function onPropertySet(obj, prop, ...callback_or_once){
    let callback, once;
    for(let arg of callback_or_once){
        switch(typeof arg){
        case "function": callback = arg; break;
        case "boolean": once = arg; break;
        }
    }


    let inner_value = obj[prop];
    let p = new Promise(resolve => Object.defineProperty(obj, prop, {
        configurable: true,
        // enumerable: true,
        get(){ return inner_value; },
        set(v){
            inner_value = v;
            if(once){
                Object.defineProperty(obj, prop, {
                    configurable: true,
                    // enumerable: true,
                    value: v,
                    writable: true,
                });
            }
            (callback || resolve)(v);
        }
    }));
    if(!callback) return p;
};

// usage
let a = {};
function sayHiValue(v){ console.log(`Hi "${v}"`); return v; }

// do
Object.onPropertySet(a, "b", sayHiValue);
a.b = 2; // Hi "2"
a.b = 5; // Hi "5"

// or
Object.onPropertySet(a, "c", true).then(sayHiValue).then(v => {
    console.log(a.c); // 4 // because a.c is set immediatly after a.c = 3
    console.log(v); // 3 // very important: v != a.c if a.c is reassigned immediatly
    a.c = 2; // property "c" of object "a" is re-assignable by '=' operator
    console.log(a.c === 2); // true
});
a.c = 3; // Hi "3"
a.c = 4; // (Nothing)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top