Fluent getters and setters

Single method working as both getter and setter

It is convenient to use the same method as a getter and setter for a property. If no value is provided as argument, the method works as a getter. If there is an argument, the method works as a setter.

person.name(); // returns name
person.name('john'); // sets name to 'john'

We can implement this feature in each method. In this example, the data will be stored in separate private variables and the object will be returned

function Person() {
  var name = 'foo'; // private data
  var p = {}; // returned object

  // attach get/set method
  p.name = function () {
    if (!arguments.length) {
      return name; // getter
    }
    name = arguments[0]; // setter
  };
  return p;
}
var p = Person();
p.name() // 'foo'
p.name('bar');
p.name() // 'bar'

Writing more than a single method like this is a recipe for hard to understand code. Let us write a small utility function to create methods that work as both getters and setters

function getSet(o, name, data, dataName) {
  o[name] = function () {
    if (!arguments.length) {
      return data[dataName];
    }
    data[dataName] = arguments[0];
  };
}

The function getSet attaches a method name to given object o. The actual value will be stored in a separate data[dataName] property. The same Person module is now much easier to read

function Person() {
  var data = {
    name: 'foo'
  };
  var p = {};
  // attach get/set method
  getSet(p, 'name', data, 'name');
  return p;
}

We can even use the same property name by default, and return the object reference in the setter mode.

function getSet(o, name, data, dataName) {
  if (arguments.length === 3) {
    dataName = name;
  }
  o[name] = function () {
    if (!arguments.length) {
      return data[dataName];
    }
    data[dataName] = arguments[0];
    return o;
  };
}
// use
p.name('jim').name() // jim