Search code examples
javascriptautomatic-properties

Does JavaScript have an equivalent way to implement c# style auto properties without massive overhead?


I'm curious if JavaScript has a way to bind a function when a property is changed without an enormous overhead like watching all the auto-properties with a timer, but without setting them via a function call. For example, I know you could do something like:

var c = new (function () {
    this.Prop = 'test';
    this.Prop_get = function (value) {
        return('Prop = ' + this.Prop);
    };
    this.Prop_set = function (value) {
        if (value != 'no') {
            this.Prop = value;
        }
    };
})();

document.write(c.Prop_get());
document.write('<BR />');
c.Prop_set('no');
document.write(c.Prop_get());
document.write('<BR />');
c.Prop_set('yes');
document.write(c.Prop_get());
document.write('<BR />');

But I'm looking for some way to allow the following to produce the same result:

document.write(c.Prop);
document.write('<BR />');
c.Prop = 'no';
document.write(c.Prop);
document.write('<BR />');
c.Prop = 'yes';
document.write(c.Prop);
document.write('<BR />');

With any changes to the pseudoclass other than adding a timer to watch the Prop property for changes or similarly high-overhead solutions.


Solution

  • I found the solution to this after coming across this link relating to getters and setters. Here is a generic method of applying properties to objects I put together as a result if anyone is interested in it:

    Object.prototype.Property = function (name, fn) {
        if (fn.hasOwnProperty('get')) { this.__defineGetter__(name, fn.get); }
        else { this.__defineGetter__(name, function () { throw ('Cannot read property ' + name + '.'); }); }
        if (fn.hasOwnProperty('set')) { this.__defineSetter__(name, fn.set); }
        else { this.__defineSetter__(name, function () { throw ('Cannot write property ' + name + '.'); }); }
    };
    
    function C() {
        var _Field = 'test';
        this.Property('Field', {
            get: function () {
                return ('Field = ' + _Field);
            },
            set: function (value) {
                if (value != 'no') {
                    _Field = value;
                }
            }
        });
    };
    C.prototype.constructor = C;
    
    var c = new C();
    document.write(c.Field);
    document.write('<BR />');
    c.Field = 'no';
    document.write(c.Field);
    document.write('<BR />');
    c.Field = 'yes';
    document.write(c.Field);
    document.write('<BR />');
    

    Edit: A JQuery-friendly Object.prototype.Property function like the above:

    Object.defineProperty(Object.prototype, 'Property', {
        enumerable: false,
        value: function (name, fn) {
            if (fn.hasOwnProperty('get')) { this.__defineGetter__(name, fn.get); }
            else { this.__defineGetter__(name, function () { throw ('Cannot read property ' + name + '.'); }); }
            if (fn.hasOwnProperty('set')) { this.__defineSetter__(name, fn.set); }
            else { this.__defineSetter__(name, function () { throw ('Cannot write property ' + name + '.'); }); }
        }
    });
    

    And a working JSFiddle.