28

I am trying to map values to a function that will accept two numbers to multiply but am having trouble doing so (if this doesn't make sense, take a look at the examples below).

I have an array of numbers and I would like to double/triple/quadruple... the values of this array. I have created functions that would do this, and am feeding these double() and triple() into map().

var arr = [1, 2, 3, 4, 5];

function double(num) {
  return num * 2;
}

function triple(num) {
  return num * 3;
}

console.log( arr.map(double) );
console.log( arr.map(triple) );

This solution is not scalable as what if I want to multiply the values by 5, or 10? I need a more abstract function that would take a parameter of what to multiply. I am confused about how to do this. My attempt so far is:

var arr = [1, 2, 3, 4, 5];

function multiply(num, multiplyBy) {
  return num * multiplyBy;
}

console.log( arr.map(multiplyBy(4) ); // Uncaught TypeError: NaN is not a function

How would I pass multiply() the multiplyBy parameter?

3 Answers 3

32

You can do something called a factory currying. Effectively, you make a function that will return another function which is tailored to your needs. In this case, an anonymous one.

var arr = [1, 2, 3, 4, 5];

function multiplyBy(scale) {
    return function(num){
        return num * scale;
    }
}

console.log( arr.map( multiplyBy(4) ));

This works because the scope of the anonymous function that is returned is within that of the factory outer function. So, whenever we produce a new function, it will retain the value of scale that was given for its production.

Edit: The last part of @Bergi 's answer is the same as mine. The concept is apparently called currying. Thanks @Bergi ! The Factory pattern is more often applied to the production of objects, as Bergi noted, but it was the only thing I could think of at the time, and javascript sort of treats functions like objects. In this specific case, they are effectively similar. Here is a good reference for currying in JavaScript

Sign up to request clarification or add additional context in comments.

3 Comments

I would use the term "factory" only for functions that return objects.
I made my answer more readable, I used the weird indentation only to make the transformation to the ES6 arrow function one-liner more obvious.
This answer is easier to understand than using .bind
24

You're looking for partial application. It can be done with bind for example (or a number of helper functions that come with functional libraries, like in Underscore):

arr.map(multiplyBy.bind(null, 4))

however a simple arrow function would be easier:

arr.map(x => multiplyBy(4, x))

But you can also get the partial application for free if you curry your multiplyBy function, taking the multiplier and returning a new function:

function multiplyBy(multiplier) {
  return function(num) {
    return num * multiplier;
  };
}
// ES6 arrow functions:
const multiplyBy = multiplier => num => num * multiplier;

arr.map(multiplyBy(4));

Comments

11

You can use Function.prototype.bind to create a new function with bound arguments. For example

var arr = [1, 2, 3, 4, 5];

function multiplyBy(multiplyBy, num) {
  // note the "num" argument must come last if it is to represent the argument from "map"
  return num * multiplyBy;
}

console.log( arr.map(multiplyBy.bind(null, 4)) ); // null is for the "this" argument

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.