Willem Mulder
Willem Mulder

Reputation: 13994

How to Monitor the Setting of new Properties on Javascript Objects

How could I get a callback whenever new properties are set on a Javascript Object..?
I.e. I don't know which properties are going to be set, but want a callback for any properties that are set.

What I want is

var obj = {};
obj.a = "something"; // triggers callback function

function callback(obj,key,val) {
    console.log(key + " was set to " + val + " on ", obj);
}

Is this possible?

Upvotes: 3

Views: 87

Answers (4)

Joshua Dwire
Joshua Dwire

Reputation: 5443

Unfortunately, JavaScript won't let you know when a property is changed. Many times I've wished it would, but since it wouldn't I've had to find a workaround. Instead of setting the property directly, set it via a setter method which triggers the callback function (and possible use a getter method to access the property too) like this:

function callback(obj,key,val) {
    console.log(key + " was set to " + val + " on ", obj);
}

var obj = {};
obj.setA=function(value){
    obj.a=value;
    callback(obj,'a',value);// triggers callback function
}
obj.getA=function(){
    return obj.a;
}

obj.setA("something");

jsFiddle: http://jsfiddle.net/jdwire/v8sJt/

EDIT: Another option if you want to completely prevent changing the property without a callback:

function callback(obj,key,val) {
    console.log(key + " was set to " + val + " on ", obj);
}

var obj={};
(function(){
   var a=null;
   obj.setA=function(value){
       a=value;
       callback(obj,'a',value);// triggers callback function
   }
   obj.getA=function(){
       return a;
   }
})()

console.log("a is "+obj.getA());// a is null
obj.setA("something"); // Set a to something
console.log("a is now "+obj.getA()); // a is now something
obj.a="something else"; // Set obj.a to something else to show how a is only accessible through setA
console.log("a is still "+obj.getA()); // a is still something

jsFiddle: http://jsfiddle.net/jdwire/wwaL2/

Upvotes: 1

Vitor Canova
Vitor Canova

Reputation: 3976

You can use the new defineProperty:

function onChange(propertyName, newValue){
...
}

var o = {};

Object.defineProperty(o, "propertyName", { 
 get: function() {return pValue; },
 set: function(newValue) { onChange("propertyName",newValue); pValue = newValue;}});

But depends on the browser version you need to support.

Edit: Added snippet on Jsfiddle, works in IE10. http://jsfiddle.net/r2wbR/

Upvotes: 4

Amberlamps
Amberlamps

Reputation: 40448

The best idea is to have setter and getter methods. But according to your previous implementation one could still alter your object properties without using setter and getter. Therfore you should make you senstive variables privat. Here is a brief example:

var Person = (function() {

    function Person() {};

    var _name;

    Person.prototype.setName = function(name) {

        _name = name;

    };

    Person.prototype.getName = function() {

        return _name;

    };

    return Person;

})();

var john = new Person();

john.getName();

// => undefined

john.setName("John");
john.getName();

// => "John"

john._name;

// => undefined

john._name = "NOT John";
john.getName();

// => "John"

Upvotes: 1

Guern
Guern

Reputation: 1257

The best thing to do it is a setter function, you don't need a getter,

var obj = {};
setKey(obj, 'a', "something"); // triggers callback function

function setKey(obj, key, val){
    obj[key] = val;
    callback(obj, key, val);
}

function callback(obj, key, val) {
    console.log(key + " was set to " + val + " on ", obj);
}

Do it as generic as you can, don't do a different function for all keys

Try it here

Upvotes: 1

Related Questions