Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing get/set methods for JavaScript property created using Object.create

What I'd like is the ability to wrap a JavaScript property to modify behavior on get/set.

For properties that are values, I can do the following:

var obj = {
    myProperty : 0
};

function notifyOfChange(obj, propertyName) {
    var propertyValue = obj[propertyName];
    Object.defineProperty(obj, propertyName, {
        get : function() { return propertyValue; },
        set : function(newValue) {
            var propertyValue = newValue;
            console.log("Message from notifyOfChange."); 
        }
    });
};

obj.myProperty = 10; // outputs "Message from notifyOfChange."

However, what if myProperty already has a getter/setter?

var obj = Object.create({}, {
    myProperty : {
        get : function() { return this._myProperty; },
        set : function(value) {
            console.log("Message from obj itself.");
            this._myProperty = value;
        },
        configurable : true
    }
});

obj.myProperty = 10; // outputs "Message from obj itself";

notifyOfChange(obj, "myProperty");

obj.myProperty = 10; // outputs "Message from notifyOfChange."

Is there a way to detect the myProperty anonymous setter so that I can call it in notifyOfChange?

Note: I'd like to make notifyOfChange work with any object, so just using a named function for the myProperty setter doesn't work.

like image 890
guy Avatar asked Dec 13 '25 16:12

guy


1 Answers

function notifyOfPropertyChange(obj, propertyName) {

    var desc = Object.getOwnPropertyDescriptor(obj, propertyName);

    if ("value" in desc && desc.writable) {
        // Value property

        var propertyValue = obj[propertyName];

        Object.defineProperty(obj, propertyName, {
            get: function () { return propertyValue; },
            set: function (newValue) {
                propertyValue = newValue;
                console.log("Message from notifyOfChange.");
            },
            configurable: true,
            enumerable: desc.enumerable
        });

    } else if (desc.set) {
        // Getter/setter property

        // Redefine the setter, keep the getter if it exists
        var originalSet = desc.set.bind(obj);
        desc.set = function (newValue) {
            originalSet(newValue);
            console.log("Message from notifyOfChange.");
        };
        Object.defineProperty(obj, propertyName, desc);
    }
}

You can use Object.getOwnPropertyNames to get the full list of property names to modify.

See MDN for an explanation of Object.getOwnPropertyDescriptor.

like image 166
kpozin Avatar answered Dec 16 '25 05:12

kpozin