Reputation: 16056
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.
Upvotes: 0
Views: 1792
Reputation: 187004
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)
Upvotes: 1
Reputation: 35760
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);
Upvotes: 2