Использование этой функциональной техники может сделать ваш код более элегантным.

Функциональное программирование дает нам методы решения проблем в нашем коде. Одно из них, частичное применение, немного сложно понять, но оно позволяет нам писать меньше (звучит интересно, правда?).

Что это?

Частичное приложение начинается с функции. Мы берем эту функцию и создаем новую с одним или несколькими аргументами, уже «установленными» или частично примененными. Это звучит странно, но уменьшит количество параметров, необходимых для наших функций.

Давайте дадим некоторый контекст, когда мы могли бы использовать частичное приложение:

const list = (lastJoin, ...items) => {
  const commaSeparated = items.slice(0,-1).join(", ");
  const lastItem = items.pop();
  return `${commaSeparated} ${lastJoin} ${lastItem}`;
}

Эта маленькая функция принимает одно слово lastJoin и произвольное число items. Первоначально list объявляет commaSeparated переменную. Эта переменная хранит разделенный запятыми объединенный массив всех элементов, кроме последнего. В следующей строке мы сохраняем последний элемент в items в переменной lastItem. Затем функция возвращается с использованием строкового шаблона.

Затем функция возвращает items в виде строки в формате списка. Например:

list("and", "red", "green", "blue");     // "red, green and blue"
list("with", "red", "green", "blue");    // "red, green with blue"
list("or", "red", "green", "blue");      // "red, green or blue"

Наша функция list позволяет нам создавать списки, когда мы хотим. Каждый создаваемый нами тип списка «и», «с», «или» является специализацией общей list функции. Разве не было бы хорошо, если бы они могли быть собственными функциями ?!

Как использовать частичное приложение

Здесь может помочь частичное применение. Например, чтобы создать функцию listAnd, мы «устанавливаем» (или частично применяем) аргумент lastJoin равным «и». Результат этого означает, что мы можем вызвать нашу частично примененную функцию следующим образом:

listAnd("red", "green", "blue");    // "red, green and blue"

Не нужно останавливаться на достигнутом. Мы можем создать множество специализированных функций, частично применив аргумент к нашей функции списка:

listOr("red", "green", "blue");      // "red, green or blue"
listWith("red", "green", "blue");    // "red, green with blue"

Для этого нам нужно создать partial служебную функцию:

const partial = (fn, firstArg) => {
  return (...lastArgs) => {
    return fn(firstArg, ...lastArgs);
  }
}

Эта функция принимает функцию fn в качестве первого параметра и firstArg в качестве второго. Он возвращает совершенно новую функцию с одним параметром lastArgs. Это собирает переданные аргументы.

Теперь, чтобы сделать нашу listAnd функцию, мы вызываем partial, передавая нашу list функцию и последнее слово соединения:

const listAnd = partial(list, "and");

Наша listAnd функция теперь принимает только произвольный список элементов. Эта функция при вызове, в свою очередь, вызовет переданную в list функцию. Мы видим, что в качестве первого аргумента будет передано «и», а после этого будет собрано lastArgs.

Мы создали частично примененную функцию. Мы можем использовать эту специализированную функцию снова и снова в нашей программе:

listAnd("red", "green", "blue");    // "red, green and blue"

Дальнейшее развитие

Функция partial, которую мы создали, призвана проиллюстрировать, как работает частичное приложение. Есть несколько отличных функциональных библиотек JavaScript, в которые встроена эта утилита, например Ramda JS.

Стоит отметить, что даже если вы новичок в частичном применении как концепции, есть все шансы, что вы ее использовали. Если вы когда-либо использовали метод .bind() для функции, это пример частичного применения. Обычно this передается в bind для задания контекста. Под капотом он частично применяет this и возвращает новую функцию.