Sequencing

Our sequence function is called with zero or more one-argument methods and returns a new one-argument method that executes them in turn.

function sequence(...fncs) {
    return function(data) { fncs.forEach(g => g.call(this, data)) };
}

Line 1 declares fncs to be a ‘rest parameter’. When sequence is called, its arguments are placed into the array bound to fncs. Line 2 constructs and returns a function that iterates over array fncs, calling each function g in the array in turn. Use of g.call(this, data) ensures that g can both the reference the receiver object (to which the method returned by sequence gets bound) as well as the data.

To try it out, we define three methods to be passed to sequence:

function setMoons(data) {
    this.nbrMoons = data;
}

function printMoons() {
    if (this.nbrMoons) {
        console.log(`${this.name} has ${this.nbrMoons} moons.`);
    }
}

function commentary() {
    if (this.nbrMoons > 8) {
        console.log(`${this.name} has a lot of moons!`);
    }
}

Next we construct the sequence of these functions and bind it to the object neptune:

const moonSeq = sequence(setMoons, printMoons, commentary);
let neptune = {name: 'Neptune'};
neptune.h = moonSeq;

Try it out:

neptune.h(14);
// Neptune has 14 moons.
// Neptune has a lot of moons!

Since moonSeq is an unbound method, we can call it on any receiver object:

mars = {name: 'Mars'};
moonSeq.call(mars, 2);
// Mars has 2 moons.

We can also sequence non-method functions that don’t reference this. To test this, we define a function generator:

function makeFnc(name) {
    return function(data) {
        console.log(`${data} runs on ${name}`);
    };
}

Sequencing three functions:

const fn = sequence(makeFnc('Air'), makeFnc('Light'), makeFnc('Music'));
fn('Earth');
// Earth runs on Air
// Earth runs on Light
// Earth runs on Music

Constructing a sequence and applying it in one fell swoop:

sequence(makeFnc('Pizza'))('Everyone')
// Everyone runs on Pizza

A sequence of zero functions produces no output and in general does nothing:

sequence()('Meat');
// <meatless>