Chain functions in JavaScript

14,157

Solution 1

So you're looking for a sort of builder pattern? You can do that like this:

class Foo {
  _passwordValidator = false;
  _optional = false;

  passwordValidator() {
    this._passwordValidator = true;
    return this;
  }
  optional() {
    this._optional = true;
    return this;
  }

  doThing() {
    if (this._optional) { /* ... */ }
    if (this._passwordValidator) { /* ... */ }
  }
}

const foo = new Foo().passwordValidator().optional();

foo.doThing();

Edit: to more directly answer your question, there is no way to wait to do something until the current chain of method calls is done; you have to call a method like doThing() in the example to signal that you actually want to do the thing now.

Solution 2

I ended up using what @coolreader18 suggested. That was exactly what I was looking for.

function func(val) {
    this._optional = false;
    this._check = false;
    
    const doStaff = (message = 'Doing staff') => {
        console.log(message);
        return;
    };


    return {
        check: function(n) {
            this._check = true;
            return this;
        },
        optional: function(n) {
            this._check = false;
            this._optional = true;
            return this;
        },
        exec: function() {
            if (this._check) doStaff();
            if (this._optional) doStaff('Maybe not');
        }
    }
}

func().check().optional().exec();

Solution 3

Calling a chained method of express-validator returns a middleware function, and as functions can have properties you can call a method on that returned function, which returns a new function with methods and so on. Chaining functions is quite easy:

 const chain = (pairs, fn = el => el) => {
   for(const [key, method] of pairs)
     fn[key] = (...opt) => chain(pairs, method(fn)(...opt));
   return fn;
};

const math = chain([
  ["add", prev => a => b => prev(b) + a],
  ["mul", prev => a => b => prev(b) * a]
]);

console.log(
  (math.add(5).mul(3).add(3))(5)
 );

Solution 4

var Obj = {
  result: 0,
  addNumber: function(a, b) {
    this.result = a + b;
    return this;
  },

  multiplyNumber: function(a) {
    this.result = this.result * a;
    return this;
  },
 
  divideNumber: function(a) {
    this.result = this.result / a;
    return this;
  }
}

Obj.addNumber(10, 20).multiplyNumber(10).divideNumber(10);

link => https://medium.com/technofunnel/javascript-function-chaining-8b2fbef76f7f

Share:
14,157
Blz
Author by

Blz

Updated on June 11, 2022

Comments

  • Blz
    Blz almost 2 years

    Is there a way to chain functions in JavaScript so when last function in chain is called we take into consideration all function in chain that was specified. Basically what I am trying to do is the same thing express-validator does: Something like this:

    check('password').passwordValidator().optional();
    

    I want to be able to call

    check('password').passwordValidator();
    

    and

    check('password').passwordValidator().optional();
    
  • John Oerter
    John Oerter over 5 years
    I believe passwordValidator and optional would both need to return this in order to be chainable, correct?
  • Blz
    Blz over 5 years
    That's exactly what I was looking for. Thank you.
  • coolreader18
    coolreader18 over 5 years
    @JohnOerter yes, of course, I feel dumb now. Blz, you do have to return this from each of the methods that you want to be part of the builder.
  • khizer
    khizer almost 3 years
    does return self does the same job? instead of returning this from methods