Getters \ setters for dummies
Solution 1
In addition to @millimoose's answer, setters can also be used to update other values.
function Name(first, last) {
this.first = first;
this.last = last;
}
Name.prototype = {
get fullName() {
return this.first + " " + this.last;
},
set fullName(name) {
var names = name.split(" ");
this.first = names[0];
this.last = names[1];
}
};
Now, you can set fullName
, and first
and last
will be updated and vice versa.
n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"
Solution 2
Getters and Setters in JavaScript
Overview
Getters and setters in JavaScript are used for defining computed properties, or accessors. A computed property is one that uses a function to get or set an object value. The basic theory is doing something like this:
var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'
This is useful for automatically doing things behind-the-scenes when a property is accessed, like keeping numbers in range, reformatting strings, triggering value-has-changed events, updating relational data, providing access to private properties, and more.
The examples below show the basic syntax, though they simply get and set the internal object value without doing anything special. In real-world cases you would modify the input and/or output value to suit your needs, as noted above.
get/set Keywords
ECMAScript 5 supports get
and set
keywords for defining computed properties. They work with all modern browsers except IE 8 and below.
var foo = {
bar : 123,
get bar(){ return bar; },
set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;
Custom Getters and Setters
get
and set
aren't reserved words, so they can be overloaded to create your own custom, cross-browser computed property functions. This will work in any browser.
var foo = {
_bar : 123,
get : function( name ){ return this[ '_' + name ]; },
set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );
Or for a more compact approach, a single function may be used.
var foo = {
_bar : 123,
value : function( name /*, value */ ){
if( arguments.length < 2 ){ return this[ '_' + name ]; }
this[ '_' + name ] = value;
}
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );
Avoid doing something like this, which can lead to code bloat.
var foo = {
_a : 123, _b : 456, _c : 789,
getA : function(){ return this._a; },
getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};
For the above examples, the internal property names are abstracted with an underscore in order to discourage users from simply doing foo.bar
vs. foo.get( 'bar' )
and getting an "uncooked" value. You can use conditional code to do different things depending on the name of the property being accessed (via the name
parameter).
Object.defineProperty()
Using Object.defineProperty()
is another way to add getters and setters, and can be used on objects after they're defined. It can also be used to set configurable and enumerable behaviors. This syntax also works with IE 8, but unfortunately only on DOM objects.
var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
get : function(){ return this._bar; },
set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;
__defineGetter__()
Finally, __defineGetter__()
is another option. It's deprecated, but still widely used around the web and thus unlikely to disappear anytime soon. It works on all browsers except IE 10 and below. Though the other options also work well on non-IE, so this one isn't that useful.
var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );
Also worth noting is that in the latter examples, the internal names must be different than the accessor names to avoid recursion (ie, foo.bar
calling foo.get(bar)
calling foo.bar
calling foo.get(bar)
...).
See Also
MDN get, set,
Object.defineProperty(), __defineGetter__(), __defineSetter__()
MSDN
IE8 Getter Support
Solution 3
You'd use them for instance to implement computed properties.
For example:
function Circle(radius) {
this.radius = radius;
}
Object.defineProperty(Circle.prototype, 'circumference', {
get: function() { return 2*Math.PI*this.radius; }
});
Object.defineProperty(Circle.prototype, 'area', {
get: function() { return Math.PI*this.radius*this.radius; }
});
c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832
Solution 4
Sorry to resurrect an old question, but I thought I might contribute a couple of very basic examples and for-dummies explanations. None of the other answers posted thusfar illustrate syntax like the MDN guide's first example, which is about as basic as one can get.
Getter:
var settings = {
firstname: 'John',
lastname: 'Smith',
get fullname() { return this.firstname + ' ' + this.lastname; }
};
console.log(settings.fullname);
... will log John Smith
, of course. A getter behaves like a variable object property, but offers the flexibility of a function to calculate its returned value on the fly. It's basically a fancy way to create a function that doesn't require () when calling.
Setter:
var address = {
set raw(what) {
var loc = what.split(/\s*;\s*/),
area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);
this.street = loc[0];
this.city = area[0];
this.state = area[1];
this.zip = area[2];
}
};
address.raw = '123 Lexington Ave; New York NY 10001';
console.log(address.city);
... will log New York
to the console. Like getters, setters are called with the same syntax as setting an object property's value, but are yet another fancy way to call a function without ().
See this jsfiddle for a more thorough, perhaps more practical example. Passing values into the object's setter triggers the creation or population of other object items. Specifically, in the jsfiddle example, passing an array of numbers prompts the setter to calculate mean, median, mode, and range; then sets object properties for each result.
Solution 5
Getters and setters really only make sense when you have private properties of classes. Since Javascript doesn't really have private class properties as you would normally think of from Object Oriented Languages, it can be hard to understand. Here is one example of a private counter object. The nice thing about this object is that the internal variable "count" cannot be accessed from outside the object.
var counter = function() {
var count = 0;
this.inc = function() {
count++;
};
this.getCount = function() {
return count;
};
};
var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());
If you are still confused, take a look at Crockford's article on Private Members in Javascript.
Admin
Updated on September 10, 2021Comments
-
Admin almost 3 years
I've been trying to get my head around getters and setters and its not sinking in. I've read JavaScript Getters and Setters and Defining Getters and Setters and just not getting it.
Can someone clearly state:
- What a getter and setter are meant to do, and
- Give some VERY simple examples?
-
Admin about 15 yearsOk, I think I'm starting to get it. I'm trying to assign a getter to the length property of an array object but getting an error: "Redeclaration of var length" And the code looks like this: obj = []; obj.__defineGetter__('length',function(){ return this.length; });
-
Montre about 15 yearsThat's because Array objects already have a builtin length property. If the redeclaration was allowed, calling the new length would recurse infinitely. Try calling the property "my_length" or some such.
-
Matthew Crumley over 13 years@Akash: No, although, Internet Explorer 9 does support the newer
Object.defineProperty
function that can define getters and setters. -
Akash Kava over 13 yearsIsnt it really painful that MS does not support JS correctly and they do not make their silverlight run everywhere, so I have to program everything twice, one for SL and one for rest of the world :)
-
devios1 about 13 yearsI disagree. Getters and setters are also very useful for encapsulating information whose definition may not just be a simple variable. It can be handy if you need to change the behavior of a system that previously used simple properties and which other things may depend on. Furthermore, your example only demonstrates "pseudo getters" which are just functions. Real JavaScript getters appear as simple values (and are accessed without function notation), hence the real power of them.
-
Martin Konicek almost 13 yearsHow do you make first and last private?
-
Matthew Crumley almost 13 years@Martin: You could make them private by using the same technique as in John's answer. If you want to use real getters/setters, you would have to use
this.__defineGetter__
or the newerObject.defineProperty
function. -
xchg.ca almost 13 yearsOnly one problem with approach listed above, if you want to add getters and setters for already existing class it will override prototypes, and original methods will not be accessible.
-
Michael Scott Asato Cuthbert almost 11 yearsthe point was to be able to change an attribute to something fancier without needing to change the public interface. Adding a call () tag changes it.
-
r0estir0bbe about 8 yearsDoesn't this approach overwrite
Name.prototype.constructor
? Seems like a bad alternative to millimoose's Answer. -
r0estir0bbe about 8 yearsIn order to define both getters in one statement, use
Object.defineProperties
. -
AgmLauncher almost 8 yearsNot sure if I would call that powerful. Something appearing as X but is really Y is not necessarily clear. I would absolutely NOT expect
var baz = foo.bar
to have a full blown set of hidden behavior behind it. I would expect that fromfoo.getBar()
, however. -
Jessica almost 8 years@MatthewCrumley Is this es6 syntax?
-
Matthew Crumley almost 8 years@Jessica Yes, although it was actually introduced in ES5.
-
Andreas over 7 yearsI still don't understand the benefit of using get and set vs creating a getMethod or setMethod. Is the only benefit that you can call it without () ? There must be another reason it's added to javascript.
-
rojo over 7 years@Andreas Getters and setters behave like properties when called, which can help articulate their intended purpose. They don't unlock otherwise missing abilities, but their use can help you organize your thoughts. That's the real benefit. As a practical example, I used to use a getter to extend a Google Maps object. I needed to calculate the camera roll angle so I could rotate map tiles flat to the horizon. Google does this automatically on the back end now; but at the time it was helpful to me to retrieve
maps.roll
as a property rather thanmaps.roll()
's return val. It's just a preference. -
Andreas over 7 yearsso it's just syntactic sugar to make code look cleaner without the (). I can't see why you couldn't your example with
maps.roll()
-
rojo over 7 years@Andreas Who says I couldn't? Like I say, it's just a way to help me keep my thoughts organized. Coding is an art. You don't ask Bob Ross why he had to use burnt ochre when he could've used orange. You may not see a need now, but one day when you decide your painting needs a little burnt ochre, it'll be on your palette.
-
Andreas over 7 years:) one thing that i see that get and set syntax does, is being auto-run if it's used as a property of a property.
-
dystopiandev over 7 yearsIn the more compact approach,
this[ '_' + name ] = value;
could bethis[ '_' + name ] = arguments[1];
and there would be no need to specifyvalue
arg. -
uzay95 over 6 yearsThis is just creating new getName, and setName methods. These are not related to create property!
-
nevf about 6 yearsThe example:
var foo = { bar : 123, get bar(){ return bar; }, set bar( value ){ this.bar = value; } }; foo.bar = 456;
Raises an exception: Uncaught RangeError: Maximum call stack size exceeded at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) -
nevf about 6 yearsThe set/get name must be different to the property name. So instead of
bar: 123
andthis.bar = value
etc. change these to_bar
for example. See: hongkiat.com/blog/getters-setters-javascript -
RegarBoy almost 6 yearsCan't you just make { "area": function () {return ...} } ? simply assign it as an object property
-
Montre almost 6 years@developer That’s not a Javascript getter as defined by the language, that’s just a function. You have to call it to get the value, it doesn’t overload access to the property. Also there’s a special circle of hell reserved for people who invent their own broken object systems in JS instead of building on the one it already has.
-
Beejor over 4 years@nevf Thanks for the correction! Yes, typically with computed properties the "real" internal one is named like
_foo
ormFoo
. If it's the same as the getter/setter, it will cause an infinite loop due to recursion and then a Stack Overflow™ ;-) because when you say a = b, it calls a.get(b) which itself calls a = b, which calls a.get(b), ... -
Stephan Luis almost 3 yearsAren't backing fields required to avoid an stack overflow/ infinite loop?
-
Shani Kehati almost 3 yearsThey might be -- I haven't really tried using a setter before. I'll update my answer and address that issue