Neues Node.js-Buch
Alle Artikel

Create a generic function for partial application

Problem

You want to create a generic function, that produces for a given function the partial applied function.

Ingredients

  • 2 functions
  • the apply() method
  • the slice() method

Directions

  1. Define a function that accepts another function (the one that should be partial applicable).

    function partial(fn /*, args...*/) {
      ...
    }
  1. Let the function return another function (this will be the partial applicable function).

    function partial(fn /*, args...*/) {
      ...
      return function() {
        ...
      }
    }
  2. Convert all but the first argument to an array by borrowing the slice() method.

    function partial(fn /*, args...*/) {
      var args = Array.prototype.slice.call(arguments, 1);
      return function() {
        ...
      };
    }
  3. Convert the arguments of the inner function to an array.

    function partial(fn /*, args...*/) {
      var args = Array.prototype.slice.call(arguments, 1);
      return function() {
        var argsInner = Array.prototype.slice.call(arguments, 0);
        ...
      };
    }
  4. Combine the arguments of the outer function with the arguments of the inner function.

    function partial(fn /*, args...*/) {
      var args = Array.prototype.slice.call(arguments, 1);
      return function() {
        var argsInner = Array.prototype.slice.call(arguments, 0);
        var argsAll = args.concat(argsInner);
        ...
      };
    }
  5. Call the passed function using the apply() method, passing the combined arguments.

    function partial(fn /*, args...*/) {
      var args = Array.prototype.slice.call(arguments, 1);
      return function() {
        var argsInner = Array.prototype.slice.call(arguments, 0);
        var argsAll = args.concat(argsInner);
        return fn.apply(this, argsAll);
      };
    }
  6. Optional: combine the previous three steps.

    function partial(fn /*, args...*/) {
      var args = Array.prototype.slice.call(arguments, 1);
      return function() {
        return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, 0)));
      };
    }
  7. Voilá, a perfect, tasteful generic function that creates partial applicable functions.

    function partial(fn /*, args...*/) {
      var args = Array.prototype.slice.call(arguments, 1);
      return function() {
        return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, 0)));
      };
    }
    function createPerson(firstName, lastName) {
      return {
       firstName: firstName,
       lastName: lastName
      }
    }
    var createPersonWithFirstNameJohn = partial(createPerson, 'John');
    var johnDoe = createPersonWithFirstNameJohn('Doe');
    console.log(johnDoe.firstName);  // "John"
    console.log(johnDoe.lastName);   // "Doe"

Alternative recipes

  • Since ES2015: use rest parameters, fat arrow functions and the spread operator (implementation will follow in a later blog post).