+7

Understanding Currying Pattern in Javascript

Hi, I'm Tuan, a Full-stack Web Developer from Tokyo 😊. Follow my blog to not miss out on useful and interesting articles in the future.

In functional programming, the currying pattern is a way of writing functions that allows us to partially apply arguments to a function. This means that we can create a new function by providing some, but not all, of the arguments that the original function expects. This can be useful for creating more specific functions that can be re-used in different parts of our code.

What is Currying?

Currying is the process of taking a function that expects multiple arguments and turning it into a sequence of functions that each expect just one argument. For example, consider the following function that adds two numbers together:

function add(x, y) {
  return x + y;
}

We can curry this function by writing a new function that takes the first argument x and returns a new function that expects the second argument y. Here's how we could do this:

function add(x) {
  return function(y) {
    return x + y;
  }
}

Now, instead of calling add(x, y), we can call add(x)(y). This might seem like a small change, but it allows us to do some interesting things.

Benefits of Currying

There are several benefits to using the currying pattern in our code:

1. Reusable Functions

One of the main benefits of currying is that it allows us to create more specific functions that can be re-used in different parts of our code. For example, consider the following function that multiplies a number by 10:

function multiplyBy10(x) {
  return x * 10;
}

This function is specific to multiplying by 10, so we couldn't use it to multiply by any other number. However, if we curry this function, we can create a more general function that can be used to multiply by any number:

function multiply(x) {
  return function(y) {
    return x * y;
  }
}

const multiplyBy10 = multiply(10);
const multiplyBy5 = multiply(5);

Now we have two specific functions, multiplyBy10 and multiplyBy5, that can be re-used throughout our code.

2. Composability

Another benefit of currying is that it allows us to easily compose new functions from existing ones. For example, consider the following functions that add and multiply numbers:

function add(x, y) {
  return x + y;
}

function multiply(x, y) {
  return x * y;
}

We can use currying to create a new function that first multiplies two numbers and then adds a third number to the result:

function add(x) {
  return function(y) {
    return x + y;
  }
}

function multiply(x) {
  return function(y) {
    return x * y;
  }
}

const multiplyAndAdd = x => y => z => add(multiply(x)(y))(z);

Now we can call multiplyAndAdd(2)(3)(4) to perform the calculation (2 * 3) + 4.

Examples of Currying in Javascript

Now that we've learned about the basics of currying and its benefits, let's take a look at some examples of how we can use this pattern in our Javascript code.

1. Partial Function Application

One common use case for currying is to create a new function that has some of the arguments pre-filled. This is known as partial function application.

For example, consider the following function that calculates the total cost of an order, including sales tax:

function calculateTotal(price, taxRate) {
  return price + (price * taxRate);
}

If we want to create a new function that calculates the total cost of an order with a specific tax rate, we can use currying to do this:

function calculateTotal(taxRate) {
  return function (price) {
    return price + price * taxRate;
  };
}

const calculateTotalWithTax8 = calculateTotal(0.08);
console.log(calculateTotalWithTax8(100)); // 108

Now we can call calculateTotalWithTax8(100) to get the total cost of an order with a price of $100 and a tax rate of 8%.

2. Creating Higher-Order Functions

Another common use case for currying is to create higher-order functions, which are functions that take other functions as arguments or return them as output.

For example, consider the following function that takes an array of numbers and a callback function, and returns a new array with the callback function applied to each element:

function map(array, callback) {
  const newArray = [];
  for (const element of array) {
    newArray.push(callback(element));
  }
  return newArray;
}

We can use currying to create a new function that pre-fills the callback argument:

function map(callback) {
  return function(array) {
    const newArray = [];
    for (const element of array) {
      newArray.push(callback(element));
    }
    return newArray;
  }
}

const mapWithMultiplyBy2 = map(x => x * 2);

Now we can call mapWithMultiplyBy2([1, 2, 3]) to get the array [2, 4, 6].

3. Creating Event Handlers

Currying can also be useful for creating event handlers in React or other Javascript libraries.

For example, consider the following function that handles a click event on a button:

function handleClick(event, id, name) {
  console.log(`Button ${id} with name ${name} was clicked!`);
  // Do something with `event`
}

We can use currying to create a new function that pre-fills the id and name arguments:

function handleClick(id, name) {
  return function(event) {
    console.log(`Button ${id} with name ${name} was clicked!`);
    // Do something with `event`
  }
}

const handleClickWithIdAndName = handleClick(1, 'Submit Button');

Now we can pass handleClickWithIdAndName to the onClick prop of a button, and it will log the appropriate message when the button is clicked.

4. Creating Custom Iterators

Currying can also be useful for creating custom iterators in Javascript.

For example, consider the following function that iterates over an array of numbers and returns the sum:

function sum(array) {
  let total = 0;
  for (const element of array) {
    total += element;
  }
  return total;
}

We can use currying to create a new function that iterates over an array and applies a callback function to each element:

function iterate(callback) {
  return function(array) {
    let total = 0;
    for (const element of array) {
      total += callback(element);
    }
    return total;
  }
}

const sum = iterate(x => x + 1);

console.log('sum([1,2,3])', sum([1,2,3])) // 9

Now we can call sum([1, 2, 3]) to get the sum of the array [2, 3, 4].

Conclusion

In this article, we learned about the currying pattern in Javascript and how it can be used to create more specific, re-usable functions and improve the composability and readability of our code. We also looked at several examples of how this pattern can be applied in practical situations. While currying may take some time to get used to, it can be a powerful tool in a functional programming workflow.

Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.

Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.

Momo: NGUYỄN ANH TUẤN - 0374226770

TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)

image.png


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí