Creating Properties

JavaScript now supports C#-style properties. From the caller point of view, a property gives an illusion of a field but works as a method. Let’s revisit the Car class we created earlier and introduce another method that returns a value and then turn that into a property.

Suppose we want to know how old a car is. The year of make is provided when an instance is created. We use the getAge() method to find the age of the car, like so:

 getAge() {
 return​ ​new​ Date().getFullYear() - ​this​.year;
 }

The method subtracts the year of make from the current year. We invoke this method using the familiar method call syntax:

 const​ car = ​new​ Car(2007);
 
 console.log(car.getAge());

That works, but getAge() is a Java-style getter. C# developers write properties instead of getter methods, and JavaScript now provides the same capability. A property may have a getter, a setter, or both. If a property has only a getter, it becomes a read-only property. We’ll take a look at setters later, but for now let’s keep our focus on the getter.

If a method merely acts as a getter—that is, it returns directly the value of a field or a computed result—then implement it as a read-only property instead of as a method. Let’s now turn the getAge() method of Car into a property.

 get​ age() {
 return​ ​new​ Date().getFullYear() - ​this​.year;
 }

The property getter uses the get keyword followed by the name of the property—age in this example. Ignoring the word get for a moment, the code is no different from writing a method named age(). Placing get in front of the method turns the method name into a property. We can’t call getAge() anymore—there’s no such method. We can’t call age() either since it’s really not a method. We have to use the property name directly to refer to it, like so:

 console.log(car.age);
 car.age = 7;

When car.age is used as an expression, JavaScript will quietly call the body of code attached to get age().

If we place car.age on the left side of an assignment, then JavaScript will look for a set age(value), where value may be replaced by any name for the parameter. Since we do not have a setter for this property, JavaScript will quietly ignore the assignment. If we use ’use strict’;—and we should; see Making Objects const—then the assignment will result in an error: Cannot set property age of #<Car> which has only a getter.

Let’s create a read-write property in Car.

 get​ distanceTraveled() { ​return​ ​this​.miles; }
 
 set​ distanceTraveled(value) {
 if​(value < ​this​.miles) {
 throw​ ​new​ Error(
 `Sorry, can't set value to less than current distance traveled.`​);
  }
 
 this​.miles = value;
 }

Although getters for properties are not allowed to take any parameters, the setters are required to take exactly one parameter.

The getter for the distanceTraveled property merely returns the value in the this.miles field. The setter for the property, however, throws an exception if the value provided is less than the current value in this.miles; otherwise, it sets the value of this.miles to the given value.

Let’s exercise this property’s getter and setter:

 const​ car = ​new​ Car(2007);
 car.drive(10);
 
 console.log(car.distanceTraveled);
 
 car.distanceTraveled = 14;
 console.log(car.distanceTraveled);
 
 try​ {
  car.distanceTraveled = 1;
 } ​catch​(ex) {
  console.log(ex.message);
 }

We first call drive(10)—that will increase the value of this.miles from the initial value of 0 to 10. Then we access the property distanceTraveled to get the current value of this.miles. Next we place the property distanceTraveled on the left-hand side of an assignment, thus passing the value of 14 to the property’s setter. Once again we access the property to get its current value of 14. Finally, within the safety net of the try-catch block, we set a value of 1 for the property. Since this value is less than the current value in this.miles, the call will result in an exception. Here’s the output from the code:

 10
 14
 Sorry, can't set value to less than current distance traveled.

A property setter is useful to perform some checks and verifications before a field is modified. Keep in mind, though, that JavaScript does not provide a way to encapsulate fields—there’s no concept of private as in other languages. You may try to hide fields from access using some tricks, but there’s really no elegant, effective way to encapsulate. If you don’t want the users of your class to use a field directly, then don’t document it and hope they’re good citizens who will not touch what hasn’t been publicized.

We’ve seen how to define instance members. Next we’ll see how to define class members.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset