fearless_fool fearless_fool - 6 months ago 10
Javascript Question

a bit of javascript metaprogramming & chainable setters

I've got a need for 'chainable' setters, allowing you to do things like:

cool_shoes = new Shoes().color('glitter').style('platform')
console.log(cool_shoes.color()) // => 'glitter'


But I've gotten tired of writing the same getter and setter code over and over, to wit:

function Shoes() { this._color = null; this._style = null; }
Shoes.prototype.constructor = Shoes;

Shoes.prototype.color = function(arg) {
if (arguments.length === 0) {
return this._color; // _slot accessor
} else {
this._color = arg; // _slot setter
return this;
};
};

Shoes.prototype.style = function(arg) {
if (arguments.length === 0) {
return this._style; // _slot accessor
} else {
this._style = arg; // _slot setter
return this;
};
};


I mean, that works, but it's a lot of repetition when you should be able to do something like along the lines of:

function createGetterSetter(getter, setter) {
return function(arg) {
if (arguments.length === 0) {
return getter();
} else {
setter(arg);
return this;
};
};
};


and then use it like this:

Shoes.prototype.color = createGetterSetter(
function() { return this._color; },
function(arg) { this._color = arg; });

Shoes.prototype.style = createGetterSetter(
function() { return this._style; },
function(arg) { this._style = arg; });


Of course as any hard-working javascript wizard knows, it won't work:
this
won't be bound to the correct value when the
getter
or
setter
is called.

Despite my best efforts to sprinkle
.bind(this)
in all the right places, I still haven't gotten it to work. This should be relatively simple, but what am I missing?

Answer

As you are aware, the issue is this is not set on getter and setter, so why don't you set it?

function createGetterSetter(getter, setter) {
  return function(arg) {
    if (arguments.length === 0) {
      return getter.call(this); // pass this to getter
    } else {
      setter.call(this, arg); // pass this to setter
      return this;
    };
  };
};

function Shoes() { this._color = null; this._style = null; }
Shoes.prototype.constructor = Shoes;

Shoes.prototype.color = createGetterSetter(
    function() { return this._color; },
    function(arg) { this._color = arg; });

Shoes.prototype.style = createGetterSetter(
    function() { return this._style; },
    function(arg) { this._style = arg; });

var cool_shoes = new Shoes().color('glitter').style('platform')
document.write(cool_shoes.color()) 

Comments