Search code examples
javascriptobject.observe

Object.observe -- not supported by all major browsers, what can I use as an alternative?


I have this function that works in Chrome, which prints to the console when a variable called finishedLoading changes values.

Object.observe(finishedLoading, function(id, oldval, newval) {
         console.log('finished loading' + id + ' went from ' + oldval + ' to ' + newval);
     }

This doesn't work in a bunch of other modern browsers (e.g. firefox, safari). Is there an alternative I can use that would be better supported? Thanks!


Solution

  • A more widely supported approach could be Object.defineProperty. defineProperty can be used to have some control on a certain property of an object for instance:

    var o = { prop: '' };
    Object.defineProperty(o, 'prop', {
      get: function() { return this.value; },
      set: function(newValue) {
        // a certain property is being changed
        alert('is changed');
        this.value = newValue; 
      }
    });
    
    o.prop = 'Johnson';
    

    The above example shows how you can use defineProperty and when prop of object o is altered a defined setter (set) is called.

    At the bottom of this reference you can see that even IE-8 supports it but only under certain conditions (IE8 only support Object.defineProperty to be used on DOM nodes).

    But be careful when using it because this would assign a property to the window object as well because of a missing this:

    var o = { b:''};
    Object.defineProperty(o, 'b', {
      get: function() { return value; },
      set: function(newValue) { value = newValue; },
    });
    
    o.b = 'abc';
    console.log(window.value); // 'abc'
    

    Way to track old value of a property

    This matches more your request:

    var o = { prop: '' };
    
    Object.defineProperty(o, 'prop', {
      get: function() { return this.propValue; },
      set: function(newValue) {
        // an certain property is being changed
        console.log('old-value: ',this['oldprop']);
        console.log('new-value: ',newValue);
        this.propValue = newValue; 
        this['oldprop'] = this.propValue;
      }
    });
    
    o['prop'] = 'joseph';
    console.log(o);
    o['prop'] = 'jack';
    console.log(o);
    o['prop'] = 'john';
    console.log(o);
    

    Observe whole Object by using Object.defineProperty

    And in addition to that you could make a function that tracks a whole object and whether any property is being changed:

    function observeObject(obj){
    
      var keys = Object.keys(obj);
    
      for(var k=0; k < keys.length; k++){
    
        var key = keys[k];
    
        (function(key){
    
          var keyName = key+'value';
          var oldKeyName = 'old'+key+'value';
    
          obj[oldKeyName] = obj[key];
    
          Object.defineProperty(obj, key, {
            get: function() { return this[keyName]; },
            set: function(newValue) {
    
              console.log('old-value: ',this[oldKeyName]);
              console.log('new-value: ',newValue);
    
              this[keyName] = newValue; 
              this[oldKeyName] = this[keyName];
    
            }
          });
    
    
    
        })(key);
    
      }
    
    }
    
    
    var person = { name : 'jack', age: 26 };
    
    observeObject(person);
    
    person.name = 'john';
    person['age'] = 27;