Recipe 12.6 Creating Smart Getter/Setter Properties

12.6.1 Problem

You want to create a class property on which you can perform calculations before setting or returning a value.

12.6.2 Solution

Use the addProperty( ) method.

12.6.3 Discussion

You can create what are called getter/setter properties for classes using the addProperty( ) method within the class's constructor. Getter/setter properties are accessed from object instances just like any other properties, but they secretly invoke methods rather than directly accessing an actual property of the same name. This allows your properties to be "smart"?you can perform calculations on the fly rather than just assigning or retrieving a simple value.

To create a getter/setter property, first create getter and setter methods for the class. The getter method should not require any parameters and should return a value. The setter method should take a single parameter and not return any value. By convention, the getter and setter methods are named getPropertyName( ) and setPropertyName( ), where PropertyName is the name of the property name they control (with the first letter capitalized).

The addProperty( ) method creates a new property with the name you specify in the first parameter. The second and third parameters passed to addProperty( ) specify the getter and setter methods. It is important that you do not include the parentheses as part of the getter and setter method names when you pass them to the addProperty( ) method (i.e., methodName( ) is wrong, and methodName is correct). For example:

// Create a new Square class.
_global.Square = function (side) {

  // Assign the value passed to the constructor to the side property.
  this.side = side;

  // Create a getter/setter property named area that uses the getArea(  ) and
  // setArea(  ) methods. Qualify the references with the this keyword so that it
  // references the methods of the instance from which the area property is invoked,
  // not some other instance. Note the lack of parentheses.
  this.addProperty("area", this.getArea, this.setArea);

// Define the getter method, which should not take any parameters. It should return a
// value, in this case the area of the square (the side length squared).
Square.prototype.getArea = function (  ) {
  return Math.pow(this.side, 2);

// Define the setter method, which should accept the new value to be assigned. It
// should not return a value, but it should set the hidden property. In this example,
// the value of side is calculated as the square root of the area.
Square.prototype.setArea = function (area) {
  this.side = Math.sqrt(area);

// Create a new square with a side of length 5.
sq = new Square(5);
trace(sq.area);  // Displays: 25

// Set the area to 36.
sq.area = 36;
trace(sq.area);   // Displays: 36
trace(sq.side);   // Displays: 6

Ideally, you should not read and write the hidden property directly from the object. Instead, use the setter method to set the property and the getter method to read it:

sq = new Square(5);
trace(sq.getArea(  ));   // Displays: 25

You can use the setter method to impose restrictions or recalculate a value before assigning it to a property. For example, an area cannot be negative, and the square root of a negative number results in an imaginary number. This version of setArea( ) converts a negative number to its absolute value to avoid such problems:

 Square.prototype.setArea = function (area) {
  this.side = Math.sqrt(Math.abs(area));

12.6.4 See Also

Recipe 12.7

    Part I: Local Recipes
    Part II: Remote Recipes