Submitted by gwagner on
The following example discussion is from the online book Web Applications with JavaScript or Java.
Already available from ES5.1 (and even supported by IE 9), JavaScript's
set
and get
methods have not been used very
widely. Their main use case is the implementation of a best practice in
Object-Oriented Programming, which recommends not to allow direct value
assignments to properties, but rather to control all value assignments in
a setter method (for instance, for validating the value or for logging
the change event). But only with the new ES6 language element
class
it becomes convenient defining setters (and getters) in a
JavaScript class.
Let's look at a simple example: defining a getter for the ISBN property of a Book class:
class Book { ... get isbn () { return this._isbn; } ... }
Notice that we use a property name like "isbn" for the name of such a
getter method and we prefix it with the keyword get
, but this
name only appears to be a property name. It can, however, not be used for
storing a value. Rather, we need to complement it with an ordinary property
(here we have chosen the name _isbn
) for storing a value.
A JS getter method is implicitly invoked by a JS engine when there is a
read access for the corresponding property, like through the expression
book.isbn
in the following code:
book = new Book("006251587X"); console.log("The ISBN is: "+ book.isbn);
JavaScript's setters and getters are implicit (you don't see them). They allow having the same semantics as explicit setter methods, but with the simple syntax of direct access. In addition to having the advantage of a simpler syntax, using implicit setters in JavaScript is also safer than using explicit setters because they decrease the likelihood of a JavaScript programmer circumventing a setter by using a direct property assignment when instead a setter should be used. In other OOP languages, like Java, this is prevented by declaring properties to be 'private'. But JavaScript does not have this option.
Let's build a more complete example: defining a class for book objects having three properties (ISBN, title and year). We first define the constructor of the class like so:
class Book { constructor (i,t,y) { // assign default values to mandatory properties this._isbn = ""; this._title = ""; this._year = 0; // is constructor invoked with arguments? if (arguments.length > 0) { // assign properties by invoking implicit setters this.isbn = i; this.title = t; this.year = y; } } ... get isbn () { return this._isbn; } set isbn (i) { var validationResult = Book.checkIsbn( i); if (validationResult instanceof NoConstraintViolation) { this._isbn = isbn; } else { throw validationResult; } } ... }
Notice that the implicit getters and setters normally access a
corresponding internal property, like _isbn
. This approach is
based on the assumption that this internal property is normally not accessed
directly, but only via its getter or setter. Since we can normally assume
that developers comply with such a rule (and that there is no malicious
developer in the team), this approach is normally safe enough. However, it
is also possible to increase the safety by generating random names for the
internal properties with the help of ES6 symbols.