Search code examples
javascriptprototypechaining

Chaining functions and keep a variable in the chain if needed


I have some code like this:

function Foo( arr, prop ) {
  this.arr = arr;
  this.isOn = prop;
}

function newFoo( arr, prop ) {
  return new Foo( arr, prop );
}

Foo.prototype = {

  a: function() {
    var result = [];
    // do something and push to result
    if ( this.prop ) // do something different with result
    return newFoo( result );
  },

  // This is the method that determines if prop = true in the chain
  b: function() {
    result = [];
    // do something and push to result
    // this time 'prop' must be 'true'
    return newFoo( result, true )
  }

};

I want to keep passing true if the previous element in the chain has prop. Obvisouly the above approach doesn't work as you can see here:

var nf = newFoo;
console.log( nf( [1,2,3] ).b().isOn ); //=> true
console.log( nf( [1,2,3] ).b().a().isOn ); //=> undefined

I know I could just return newFoo( result, this.prop ) all the time on every method but I was curious to see if there are any other solutions to this problem. As methods grow in number it'll be hard to keep track of this property over time.


Solution

  • As methods grow in number it'll be hard to keep track of this property over time.

    You could just create an extra method with the functionality of newFoo that automatically keeps track of the properties you are not going to overwrite:

    function Foo( arr, prop ) {
      this.arr = arr;
      this.isOn = prop;
    }
    
    Foo.prototype = {
    
      clone: function newFoo( arr, prop ) {
        return new Foo(
          arguments.length >= 1 ? arr : this.arr,
          arguments.length >= 2 ? prop : this.isOn
        );
      },
    
      a: function() {
        var result = [];
        // do something and push to result
        if ( this.prop ) // do something different with result
        return this.clone( result );
      },
    
      // This is the method that determines if prop = true in the chain
      b: function() {
        result = [];
        // do something and push to result
        // this time 'prop' must be 'true'
        return this.clone( result, true )
      }
    
    };
    

    I've used arguments.length here to check whether a parameter was passed, you could as well test against undefined or use simple arr || this.arr for always-truthy properties.