Last Updated: February 25, 2016
·
3.895K
· bzdzb

Python style @property methods in JavaScript

If you have a value you want to make private and accessible as a class attribute, or if you want to implicitly call a custom get/set function when referencing or assigning to an attribute, Python provides the @property decorator.

Python Example

class Foo(object):
    def __init__(self):
        self._bar = 0

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, val):
        self._bar = val

Usage

foo = Foo()
print(foo.bar)  # 0
foo.bar = 42
print(foo.bar)  # 42
foo.bar += 1
print(foo.bar)  # 43

You can achieve the same behavior in JavaScript by defining getter/setter pseudo-properties using get and set operators in your constructor.

JavaScript Example

function Foo() {
  var that = Object.create(Foo.prototype);
  that._bar = 0;
  return that;
}
Foo.prototype =  {
  get bar() { return this._bar; },
  set bar(value) { return this._bar = value; }
};

Usage

foo = Foo();
console.log(foo.bar);  // 0
foo.bar = 42
console.log(foo.bar);  // 42
foo.bar += 1;
console.log(foo.bar);  //  43

JavaScript Validation Example

For example, you could use this to validate values on assignment.

function LivingPerson() {
  var that = Object.create(LivingPerson.prototype);
  that._age = undefined;
  that._name = "";
  that.minAge = 1;
  that.maxAge = 130;
  return that;
}
LivingPerson.prototype = {
  // age property get/set methods
  get age() { return this._age; },
  set age(yrs) {
    if (typeof yrs !== 'number' || isNaN(yrs) || yrs % 1 !== 0) {
      throw new TypeError('year must be a whole number');
    }
    if (yrs < this.minAge || yrs > this.maxAge) {
      throw new RangeError(
          'year must be between ' + this.minAge + ' & ' + this.maxAge);
    }
    return this._age = yrs;
  },
  // name property get/set methods
  get name() { return this._name; },
  set name(fullName) {
    if (typeof fullName !== 'string' || 
        fullName.split(' ').length < 2) {
      throw new TypeError(
          'name must be a string containing first and last name.');
    }
    return this._name = fullName;
  }
};

Usage

bob = LivingPerson();
console.log(bob.age);  // undefined
console.log(bob.name); // ''
bob.name = 'Bob';
// TypeError: name must be a string containing first and last name.
bob.age = 0;
// RangeError: year must be between 1 & 130
bob.age = 6.5;
// TypeError: year must be a whole number
bob.age = 6;
console.log(bob.age);
// 6
bob.name = 'Bob Bobson';
console.log(bob.name);
// Bob Bobson

Have a fresh tip? Share with Coderwall community!

Post
Post a tip
Did you know?

JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.

Security insights from Cside