简体   繁体   中英

JavaScript object with public getter and setter methods

Yesterday, I posted about prototypal inheritance and constructors . I finally settled on an approach that keeps the code nice and tidy and leaves the prototype alone at the cost of possibly minor performance impact:

function Card(value) {
    // setValue is a public instance method
    this.setValue = function (val) {
        if (!range[val]) {
            val = drawRandom();
        }

        // value is a public instance variable
        this.value = val;

        return val;
    };

    this.setValue(value);
}

My problem with this approach, however, is that I have to call the setValue method whenever I want to set the value of a Card instance to get the validation. What I'd like to do instead is have a custom setter method. Here's what I have so far:

function Card(val) {
    // value is a private instance variable
    var value;

    // This is a private instance method
    // It's also self-invoking, but that's beside the point
    (function (x) {
        if (!range[x]) {
            x = drawRandom();
        }

        value = x;
    }(val));

    this.__defineGetter__("value", function () {
        return value;
    });

    // Some code duplication
    this.__defineSetter__("value", function (x) {
        if (!range[x]) {
            return false;
        }

        value = x;

        return x;
    });
}

This works well. Calling var card = new Card() gives me an instance with a random value, and calling card.value = null fails because it's out of range.

My problem with this, other than the fact that it is obviously much longer, is it seems like I'm duplicating some of the code. It would be nice if the setter method was called along with the constructor. That way, I could eliminate the whole self-invoking private instance method.

Functions are first class objects in Javascript, so you can totally just do something like this to eliminate the duplication:

function setter (x) {
    if (!range[x]) {
        return false;
    }
    return x;
}
(function (x) {
    value = setter(x);
    if (!value) {
        value = drawRandom();
    }

}(val));

this.__defineGetter__("value", function () {
    return value;
});

// Some code duplication
this.__defineSetter__("value", setter);

First, you should always set the value with obj.value = newValue , even internally, because it invokes your validation. When in the constructor that means:

this.value = val;

But that won't work if you do it before the setter and getter are declared. So move it after so that the setter function will exist when it's set.


Working example here: http://jsfiddle.net/8tCjm/4/

var drawRandom = function () {
    return Math.floor(Math.random() * 3) + 1;
};

var range = {
    1: 'Ace',
    2: 'Two',
    3: 'Three'
};

function Card(val) {
    var value;

    this.__defineGetter__('value', function () {
        return value;
    });

    this.__defineSetter__('value', function (x) {
        if (range[x]) {
            value = x;
        } else {
            value = drawRandom();
        }

        return value;
    });

    this.value = val;
};

console.log(new Card(1).value); // 1
console.log(new Card(2).value); // 2
console.log(new Card(3).value); // 3

console.log(new Card(987).value); // not 987 (1-3)
​

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM