It is with much happiness that I think I can finally say, without seeming like a fool, that: "JavaScript Getters and Setters are now prevalent enough to become of actual interest to JavaScript developers." Wow, I've been waiting a long time to be able to say that.
I want to start by giving a whirlwind tour of Getters and Setters and why they're useful. Followed by a look into what platforms now support Getters and Setters as to make them relevant.
Getters and Setters
Getters and Setters allow you to build useful shortcuts for accessing and mutating data within an object. Generally, this can be seen as an alternative to having two functions with an object that are used to get and set a value, like so:{
getValue: function(){
return this._value;
},
setValue: function(val){
this._value = val;
}
}
getValue: function(){
return this._value;
},
setValue: function(val){
this._value = val;
}
}
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
// => "test2"
field.value
// => undefined
field.setValue("test2")
field.getValue()
// => "test2"
var field = new Field("test");
field.value
// => test
field.value = "test2";
field.value
// => "test2"
field.value
// => test
field.value = "test2";
field.value
// => "test2"
function Field(val){
var value = val;
this.__defineGetter__("value", function(){
return value;
});
this.__defineSetter__("value", function(val){
value = val;
});
}
var value = val;
this.__defineGetter__("value", function(){
return value;
});
this.__defineSetter__("value", function(val){
value = val;
});
}
function Field(val){
this.value = val;
}
Field.prototype = {
get value(){
return this._value;
},
set value(val){
this._value = val;
}
};
this.value = val;
}
Field.prototype = {
get value(){
return this._value;
},
set value(val){
this._value = val;
}
};
Here's another example, allowing a user to access an array of usernames (but denying them access to the original, underlying user objects.
function Site(users){
this.__defineGetter__("users", function(){
// JS 1.6 Array map()
return users.map(function(user){
return user.name;
});
};
}
this.__defineGetter__("users", function(){
// JS 1.6 Array map()
return users.map(function(user){
return user.name;
});
};
}
// Helper method for extending one object with another
function extend(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g )
a.__defineGetter__(i, g);
if ( s )
a.__defineSetter__(i, s);
} else
a[i] = b[i];
}
return a;
}
function extend(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g )
a.__defineGetter__(i, g);
if ( s )
a.__defineSetter__(i, s);
} else
a[i] = b[i];
}
return a;
}
Additionally, in my custom extend() method you'll notice two new methods: __lookupGetter__ and __lookupSetter__. These are immensely useful, once you start dealing with getters and setters.
For example, when I did my first pass at writing an extend() method, I started getting all sorts of errors - I was thoroughly confused. That's when I realized that two things were happening with the simple statement: a[i] = b[i];
If a setter existed in object a, named i, and a getter existed in object b, named i, a[i]'s value was being set not to the other setter function, but to the computed value from b's getter function. The two __lookup*__ methods allow you to access the original functions used for the methods (thus allowing you to write an effective extend method, for example).
A couple things to remember:
- You can only have one getter or setter per name, on an object. (So you can have both one value getter and one value setter, but not two 'value' getters.)
- The only way to delete a getter or setter is to do: 'delete object[name];' Be aware, that this command is capable of deleting normal properties, getters and setters. (So if all you want to do is remove a setter you need to backup the getter and restore it afterwards.)
- If you use __defineGetter__ or __defineSetter__ it will silently overwrite any previous named getter or setter - or even property - of the same name.
Platforms
Now, here is where things get really interesting. Up until just recently, talking about actually using getters and setters (outside of the context of Firefox/Gecko) was pretty much not happening.However, look at this line up:
Browsers
- Firefox
- Safari 3+ (Brand New)
- Opera 9.5 (Coming Soon)
javascript:foo={get test(){ return "foo"; }};alert(foo.test);
- SpiderMonkey
- Rhino 1.6R6 (New)
- ActionScript
- JScript.NET 8.0
Комментариев нет:
Отправить комментарий