Object.watch () para todos os navegadores?

118

Observe que Object.Watche Object.Observeambos estão obsoletos agora (em junho de 2018).


Eu estava procurando uma maneira fácil de monitorar um objeto ou variável quanto a alterações e descobri Object.watch()que isso é compatível com os navegadores Mozilla, mas não com o IE. Então comecei a pesquisar para ver se alguém havia escrito algum tipo de equivalente.

Praticamente a única coisa que encontrei foi um plugin jQuery , mas não tenho certeza se esse é o melhor caminho a seguir. Eu certamente uso jQuery na maioria dos meus projetos, então não estou preocupado com o aspecto jQuery ...

De qualquer forma, a pergunta: Alguém pode me mostrar um exemplo funcional desse plugin jQuery? Estou tendo problemas para fazer funcionar ...

Ou alguém conhece alguma alternativa melhor que funcione em qualquer navegador?

Atualizar após as respostas :

Obrigado a todos pelas respostas! Experimentei o código postado aqui: http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html

Mas eu não conseguia fazer funcionar com o IE. O código abaixo funciona bem no Firefox, mas não faz nada no IE. No Firefox, cada vez que watcher.statusé alterado, o document.write()in watcher.watch()é chamado e você pode ver a saída na página. No IE isso não acontece, mas posso ver que watcher.statusestá atualizando o valor, pois a última document.write()chamada mostra o valor correto (tanto no IE quanto no FF). Mas, se a função de retorno de chamada não for chamada, isso é meio inútil ... :)

Estou esquecendo de algo?

var options = {'status': 'no status'},
watcher = createWatcher(options);

watcher.watch("status", function(prop, oldValue, newValue) {
  document.write("old: " + oldValue + ", new: " + newValue + "<br>");
  return newValue;
});

watcher.status = 'asdf';
watcher.status = '1234';

document.write(watcher.status + "<br>");
SeanW
fonte
2
IIRC você pode usar onPropertyChange no IE
scunliffe de
1
Substitua document.write () por alert (). Deve funcionar muito bem.
Ionuț G. Stan

Respostas:

113

(Desculpe pela postagem cruzada, mas esta resposta que dei a uma pergunta semelhante funciona bem aqui)

Eu criei um pequeno objeto. Observe o shim para isso há algum tempo. Funciona no IE8, Safari, Chrome, Firefox, Opera, etc.

Eli Gray
fonte
10
Uma explicação sobre como usá-lo e como funciona internamente seria bom para aqueles de nós que não são mestres JS, obrigado.
maraujop
jsfiddle.net/kSWxP DICA: use Firefox (a última declaração não é impressa no Chrome)
Mars Robertson
Eu sabia que a ideia Object.defineProperty()existia. Acabei olhando a referência do MDN para ver como funcionava.
jumpnett
19

Esse plug-in simplesmente usa um cronômetro / intervalo para verificar repetidamente se há alterações em um objeto. Talvez bom o suficiente, mas pessoalmente gostaria de mais imediatismo como um observador.

Aqui está uma tentativa de trazer watch/ unwatchpara o IE: http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html .

Isso muda a sintaxe da maneira do Firefox de adicionar observadores. Ao invés de :

var obj = {foo:'bar'};
obj.watch('foo', fooChanged);

Você faz:

var obj = {foo:'bar'};
var watcher = createWatcher(obj);
watcher.watch('foo', fooChanged);

Não tão gentil, mas como um observador, você é notificado imediatamente.

Crescent Fresh
fonte
Sim, observe os timestamps ... não há necessidade de downvote, também crescentfresh adicionou mais informações ao post, mesmo que fosse o mesmo link. Enquanto isso, tentei o código encontrado nessa página e ainda vejo um problema. Posso estar negligenciando algo, no entanto. Eu atualizei meu post original com mais informações ...
SeanW
13

As respostas a esta pergunta estão um pouco desatualizadas. Object.watch e Object.observe estão obsoletos e não devem ser usados.

Hoje, você pode usar o objeto Proxy para monitorar (e interceptar) as alterações feitas em um objeto. 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;
  }
});

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

Se você precisa observar as alterações feitas em um objeto aninhado, você precisa usar uma biblioteca especializada. I publicado Observable Magro e 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}}]
Elliot B.
fonte
12

Resposta Atual

Use o novo objeto Proxy , que pode observar as mudanças em seu destino.

let validator = {
    set: function(obj, prop, value) {
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError('The age is not an integer');
            }
            if (value > 200) {
                throw new RangeError('The age seems invalid');
            }
        }

        // The default behavior to store the value
        obj[prop] = value;

        // Indicate success
        return true;
    }
};

let person = new Proxy({}, validator);

person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception

Resposta antiga de 2015

Você poderia ter usado Object.observe () do ES7 . Aqui está um polyfill. Mas Object.observe () agora está cancelado . Desculpe gente!

mikemaccana
fonte
Hm, não consegui fazer este polyfill funcionar no ios safari. Recebo o erro: undefined não é uma função (avaliando 'Object.observe (a.imgTouch, function (a) {console.debug ("lastX:" + a)})')
infomofo
@infomofo Olá, gostaria de abrir um fascículo na página do projeto, com todos os detalhes que puder dar? Não testei no iOS, mas vou analisar o problema.
MaxArt de
6

Observe que no Chrome 36 e superior você também pode usar Object.observe. Na verdade, isso é parte de um futuro padrão ECMAScript, e não um recurso específico do navegador como o do Mozilla Object.watch.

Object.observesó funciona nas propriedades do objeto, mas tem muito mais desempenho do que Object.watch(o que é feito para fins de depuração, não para uso em produção).

var options = {};

Object.observe(options, function(changes) {
    console.log(changes);
});

options.foo = 'bar';
Husky
fonte
1
Como em 2018, ele foi descontinuado e não é mais compatível com todos os principais navegadores
Sergei Panfilov
4

você pode usar Object.defineProperty .

observe a propriedade baremfoo

Object.defineProperty(foo, "bar", {
  get: function (val){
      //some code to watch the getter function
  },

  set: function (val) {
      //some code to watch the setter function
  }
})
souparno majumder
fonte
Isso é ótimo! Mas eu iria modificá-lo um pouco :) Para não sobrescrever o setter original. Eu faria referência foo._someObject = foo.someObject
calmbird
simples e
elegante
1

Eu usei Watch.js em um de meus projetos. E está funcionando bem. Uma das principais vantagens de usar esta biblioteca é:

"Com Watch.JS você não terá que mudar a maneira como você desenvolve."

O exemplo é dado abaixo

//defining our object however we like
var ex1 = {
	attr1: "initial value of attr1",
	attr2: "initial value of attr2"
};

//defining a 'watcher' for an attribute
watch(ex1, "attr1", function(){
	alert("attr1 changed!");
});

//when changing the attribute its watcher will be invoked
ex1.attr1 = "other value";
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src/watch.min.js"></script>

Isso é tão simples quanto isso!

NIKHIL CM
fonte