Elliot Bonneville
Elliot Bonneville

Reputation: 53311

Is there a way to detect when an object's properties have been changed?

How can I detect if an object's properties have changed in Javascript? I'm specifically looking to call a function when the amount of properties on an object has changed (whether it has gained or lost properties). I'd like to avoid using methods and to set and change the object's properties as that would get rather clumsy rather quickly, and setInterval is obviously not an option. So, is this possible?


Edit: I'm specifically looking for a way to get the length of an object's properties via a length property similar to what's on the Array object. I assumed they changed the length whenever an index was added or removed, but apparently this isn't the case. How did the original designers of Javascript manage this?

Upvotes: 2

Views: 158

Answers (3)

Šime Vidas
Šime Vidas

Reputation: 185923

So, to sum up everything I said via comments: ES6 will provide proxies which should enable handlers for events like "new property", or "property deleted". (I haven't looked into it that much, though.) Unfortunately, it will take years until proxies become cross-browser.

As for, the length property for objects, you could define a getter function for that, but that would break in IE8, since IE only implemented getters in IE9. So, that leaves you with a length() method. So:

function objectLength () {
    return Object.keys( this ).length;
}

and then, you make sure that your object has this function (either as an own property, or an inherited property):

yourObj.length = objectLength;

or

YourConstructor.prototype.length = objectLength;

Upvotes: 1

Daniel Szabo
Daniel Szabo

Reputation: 7281

The short answer, based on your requirements, is that it is not possible to do what you're trying to do. At least, not yet. There are a few techniques you can use to get the same functionality with a minimal impact on your code. Here's one of my personal favorites -- discovered somewhere on SO -- I'll link if I can find.

function myObj(){

   var _this = this;

   // onUpdate callbacks
   this.onBeforeUpdate = [];
   this.onAfterUpdate  = [];

   this.UpdateProperty = function( prop, value ){

      // execute onBeforeUpdate callbacks...  
      for ( var i = 0; i < _this.onBeforeUpdate.length; i++ )
         _this.onBeforeUpdate[i]();

      _this[prop] = value;

      // execute onAfterUpdate callbacks...
      for ( var i = 0; i < _this.onAfterUpdate.length; i++ )
         _this.onAfterUpdate[i]();
   };

}

Of course, this example can be made to perform even better with some liberal use of prototype assignments, but you can see the intent.

Upvotes: 1

Joseph
Joseph

Reputation: 119847

Well, the common way to do it is to have a getter and setter type of functions to do it, similar to how backbone does it's models. You modify the data via the function, then the function does additional processing (like execute listeners, check properties etc.) before executing what you want to do.

function ListenableObject(data){

    var that = this;
    this.data = data;
    this.listeners = [];

    this.edit = function(newvalues){
        //modify data
        //execute listeners
    }

    this.addListener = function(callback){
        that.listeners.push(callback);
    }
}

var mydata = new ListenableObject({'foo':'bar'});

mydata.addListener(function(){...callback...});

mydata.edit(somedata);

Upvotes: 2

Related Questions