# Computed Properties

## Overview

Computed properties are properties derived from the value of one or more properties on the current instance. For example, the `fullName` property on the `Person` class is defined as a method. But, we could define it as a property based on the `firstName` and `lastName` property.&#x20;

Unlike methods, computed properties are accessed like any other data property defined on the class itself. Likewise, computed properties can optionally be iterated over.

## Types of Computed Properties

We support the following types of computed properties:

* [Read-Write Properties](#read-write-properties)
* [Read-only Properties](#read-only-properties)
* [Constant Properties](#constant-properties)

### Read-Write Properties

*Read-write properties* are defined using the `computed()` method, and passing it an initialization hash. The should have a getter method, and an optional setter method. Let's see how we can redefine our `Person` class using computed properties.

{% code title="person.js" %}

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  fullName: computed ({
    set (value) {
      [this.firstName, this.lastName] = value.split (' ');    
    }
    
    get () {
      return `${this.firstName} ${this.lastName}`;
    }
});
```

{% endcode %}

{% hint style="info" %}
Use the `computed()` method to define computed property on the class definition.
{% endhint %}

&#x20;We can then just use the computed property like any other data property.

```javascript
let person = new Person ({firstName: 'Bill', lastName: 'Clinton'});
console.log (person.fullName);            // "Bill Clinton"

person.fullName = 'Ronald Reagan';
console.log (person.fullName);            // "Ronald Reagan"
```

### Read-Only Properties

*Read-only properties* are defined in a similar manner as read-write properties. The main difference read-only properties do not have a `set` method on its computed property definition.

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  fullName: computed ({
    set (value) {
      [this.firstName, this.lastName] = value.split (' ');    
    }
});
```

Now, anytime we set the `fullName` property, it will not change.

```javascript
let person = new Person ({firstName: 'Bill', lastName: 'Clinton'});
console.log (person.fullName);            // "Bill Clinton"

person.fullName = 'Ronald Reagan';
console.log (person.fullName);            // "Bill Clinton"
```

### Constant Properties

*Constant properties* are computed properties that do not change. The behavior of a constant property is therefore similar to that of [read-only properties](#read-only-properties). The main difference is the constant properties are not computed at run-time. Instead, you must provide its value when you are defining the property.

Here is an example of defining a constant property named `MINIMUM_AGE` on the `Person` class.

{% code title="person.js" %}

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  /// ...
  MINIMUM_AGE: computed.constant (21)
});
```

{% endcode %}

## Enumerable Computed Properties

When you enumerate the properties of an object, computed properties are not included in the enumeration. To enable enumeration of computed properties, add the `enumerable` property to the computed property descriptor.

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  fullName: computed ({
    enumerable: true,      // the property can be enumerated
    get () { return `${this.firstName} ${this.lastName}`; }
    set (value) { [this.firstName, this.lastName] = value.split (' '); }
});
```

For [constant properties](#constant-properties), add the property descriptor after the constant value.

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  /// ...
  MINIMUM_AGE: computed.constant (21, {enumerable: true})
});
```

Now, the computed properties will appear when the properties of the parent object are enumerated.

## Configurable Computed Properties

By default, computed properties are not configurable. This means that once a property is defined on a object, it cannot be redefined. For example, neither an extended class cannot change the property definition, nor an object instance during initialization time.&#x20;

To change this behavior, use the `configurable` property on the property descriptor.

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  fullName: computed ({
    configurable: true,      // the property is configurable
    get () { return `${this.firstName} ${this.lastName}`; }
    set (value) { [this.firstName, this.lastName] = value.split (' '); }
});
```

For [constant properties](#constant-properties), add the `configurable` property to the property descriptor after the value.

```javascript
const { BO, computed } = require ('@onehilltech/blueprint');

const Person = BO.extend ({
  /// ...
  MINIMUM_AGE: computed.constant (21, {configurable: true})
});
```

Now, you can redefine the property in extended classes and during object initialization.
