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

I'm curious if JavaScript has a way to bind a function when a property changes without the huge overhead of looking at all the automatic properties with a timer, but without setting them up through a function call. For example, I know that 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 am looking for a way to do the following to get 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 pseudo class other than adding a timer to watch the Prop property for changes or similar high load decisions.

+3


source to share


2 answers


I found a solution to this question after following this link pertaining to getters and setters . Here is a general method of applying properties to objects that I have collected as a result, in case 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: JQuery compatible Object.prototype.Property function as 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 .

0


source


Any solution to this problem boils down to what you need to maintain.

If you want IE6-IE8, it might be wiser to resort to timers or horrendous DOM abuse to make changes to hidden DOM objects that will fire listenable events, etc.

There are several blogs out there that have talked about their efforts to shrink these browsers to suit some kind of mutation library.
Results and caveats vary.

If you're talking about ES5 compliant browsers, most of them support "get" and "set" keywords directly inside objects.
This can lead to a cleaner designers / interfaces than to C #, because designers can be as simple as var a = {};

, but you also get a magic methods, rather than Java list getX

, getY

, z

and headache, trying to remember what method and which property when you get to the interface.

Seriously, this is pretty cute:

var person = {
    person_name : "Bob",
    get name () { return this.person_name; },
    set name (value) {
        console.log("But my parents named me " + this.person_name + "!");
    }
};


person.name;
person.name = "Mark";

      

But the problem is here: person.person_name

it is not private at all.
Someone can jump in and change this.

Don't bother - get

and set

shouldn't actually work with object properties.

var Person = function (name, age) {
    // we don't need to save these; closures mean they'll be remembered as arguments
    // I'm saving them as `private_*` to illustrate
    var private_name = name,
        private_age  = age;

    var public_interface = {
        get name () { return private_name; },
        set name (value) { console.log("Nope!"); },
        get age () { return private_age; },
        set age (value) { console.log("Nope!"); },
        set court_appointed_name (value) {
            console.log("If I must...");
            private_name = value;
        }
    };

    return public_interface;
};

var mark = Person("Mark", 32);
mark.name; // "Mark";
mark.name = "Bubba"; // log: "Nope!";
mark.name; // "Mark";
mark.court_appointed_name = "Jim-Bob"; // log: "If I must..."
mark.name; // "Jim-Bob"

      



You can also force the submission of jobs in objects using auth-tokens etc.

mark.name = {
    value : "Jimmy Hoffa",
    requested_by : system.user.id,
    auth : system.user.auth.token
};

      

It's all fantastic, isn't it? Why don't we do this?

Browser support.

The problem with this requires a new syntax: all objects are defined as key-value pairs.
Flashing with syntax means any non-supporting browser will crash and write unless you wrap your entire program in try / catch (which is performance suicide).

You can do one try-catch and lazy-load awesome interface test, versus bogus workarounds, on the loading page, which is the correct way to do this, but now you are developing two versions of the application.

Or three versions as the case may be (new browsers, intermediate browsers like FF3, and hacks for Ghetto_IE).

Intermediate browsers used {}.__defineGetter__

and {}.__defineSetter__

.
Object.prototype.defineProperty

(/ .defineProperties

) are methods that bring hope of IE compatibility until you realize that older versions of IE only support mutations on DOM objects (attached to the actual DOM tree), hence the headaches. Hooray.

+2


source







All Articles