Implementing Getters and Setters in JavaScript
Introduction
In JavaScript, getters and setters play a crucial role in defining computed properties or accessors. A computed property involves using functions to get or set the value of an object. Let’s illustrate this concept:
var person = { /* ... object with getters and setters ... */ };
person.email = 'example@email.com'; // triggers database update
console.log( person.username ); // outputs 'example'
console.log( person.city ); // outputs 'Anytown, USA'
Getters and setters enable automating actions when accessing a property, such as maintaining number ranges, reformatting strings, generating value-changed alerts, updating related data, granting access to private properties, etc.
The following examples demonstrate the basic syntax, but in real-world scenarios, you would customize input/output values based on your requirements, as mentioned earlier.
Using Keywords: get/set
ECMAScript 5 introduced the get
and set
keywords for defining computed properties. These keywords are supported by modern browsers, except for IE 8 and older versions.
var example = {
age : 25,
get age(){ return age; },
set age( val ){ this.age = val; }
};
example.age = 30;
var currentAge = example.age;
Customizing Getters and Setters
Since get
and set
aren't reserved words, you can redefine them to create your own cross-browser computed property functions. This approach will function across all browsers.
var example = {
_age : 25,
get : function( prop ){ return this[ '_' + prop ]; },
set : function( prop, val ){ this[ '_' + prop ] = val; }
};
example.set( 'age', 30 );
var currentAge = example.get( 'age' );
Alternatively, a more concise method is possible using a single function.
var example = {
_age : 25,
fetch : function( prop ){
if( arguments.length < 2 ){ return this[ '_' + prop ]; }
this[ '_' + prop ] = val;
}
};
example.fetch( 'age', 30 );
var currentAge = example.fetch( 'age' );
Avoid the pattern below as it can lead to code bloat.
var example = {
_a : 25, _b : 50, _c : 75,
getA : function(){ return this._a; },
getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};
To ensure security, the internal property names are prepended with underscores. This practice discourages direct access like example.name
, encouraging the use of example.get('name')
instead to retrieve a cleansed value. Conditional statements can be employed to execute different operations based on the accessed property name (prop
).
Object.defineProperty() Functionality
An alternative to getters and setters is the Object.defineProperty()
method, which allows adding these features to objects post-definition. It also enables setting configurable and enumerable behaviors. This mechanism works even on IE 8, albeit limited to DOM objects only.
var example = { _age : 25 };
Object.defineProperty( example, 'age', {
get : function(){ return this._age; },
set : function( val ){ this._age = val; }
} );
example.age = 30;
var currentAge = example.age;
Legacy Approach: __defineGetter__()
Although deprecated, __defineGetter__()
remains popular online and is compatible with most browsers (excluding IE 10 and below). Nevertheless, given the availability of better alternatives that work effectively across various environments, its relevance may diminish over time.
var example = { _age : 25 };
example.__defineGetter__( 'age', function(){ return this._age; } );
example.__defineSetter__( 'age', function( val ){ this._age = val; } );
It's essential to utilize distinct names for internal properties versus accessor names in the latter case to prevent recursion (example.age
calling example.get(age)
calling example.age
, creating a loop).
Further Reading
For detailed information on get, set,
Object.defineProperty(), __defineGetter__(), __defineSetter__(), visit MDN.
Explore more about IE8 support for getters through IE8 Getter Support documentation.