
В предыдущем видео мы с вами разобрали, зачем нужна функция curry и реальные примеры ее применения.
В этом же видео мы с вами попробуем написать функцию curry самостоятельно, для лучшего понимания того, как она работает. Замечу также, что на собеседованиях часто любят спрашивать: "Знаете ли вы каррирование? А зачем оно нужно? А функцию curry написать на бумажке можете?".
Давайте попробуем.
У меня есть файл html, где подключен наш javascript файл.
Давайте добавим простую функцию, на которой будем тестировать каррирование. Эта функция просто будет складывать 3 числа.
var add = function (a, b, c) {
return a + b + c
}
И добавим переменную curriedAdd
var curriedAdd = curry(add)
Теперь давайте, чуть выше, создадим curry функцию. Она будет принимать на вход функцию. В нашем случае функцию add.
var curry = function (fn) {
}
Теперь нам необходимо найти общее количество аргументов в функции, которую мы передали на вход. Это можно сделать с помощью .length.
var curry = function (fn) {
var arity = fn.length
}
Давайте добавим console.log и посмотрим в браузер. У нас вывелось 3, так как у нас 3 аргумента в функции add.
Как мы помним, каррируемая функция всегда возвращает функцию. Давайте добавим ее.
var curry = function (fn) {
var arity = fn.length
return function f1(...args) {
console.log('f1 args', args)
}
}
var add = function (a, b, c) {
return a + b + c
}
var curriedAdd = curry(add)
var result = curriedAdd(1)
console.log('result', result)
Напомню, что три точки - это оператор spread. Это оператор из es6, который, в нашем случае, возвращает все аргументы.
Если мы вызовем curriedAdd и передадим в нее 1, то в консоли мы увидим, что наша функция f1 вызвалась и в args у нас содержится массив с нашим аргументом 1.
Также, обратите внимание, что arity, которую мы описали ранее, с момента, когда мы создали переменную curriedAdd, хранится в замыкании. Именно поэтому, мы можем ее сейчас использовать внутри функции f1.
Что нам осталось еще написать? Мы хотим проверить передали ли нам достаточно аргументов, чтобы вызвать функцию или нет.
var curry = function (fn) {
var arity = fn.length
return function f1(...args) {
console.log('f1 args', args)
if (args.length >= arity) {
console.log('enough arguments')
} else {
console.log('need more arguments')
}
}
}
Если мы посмотрим в браузер, то увидим сообщение, что аргументов недостаточно.
Давайте сначала добавим содержимое if, потому что оно проще. Если мы получили достаточно аргументов, мы хотим вызвать исходную функцию fn с args и вернуть результат.
var curry = function (fn) {
var arity = fn.length
return function f1(...args) {
console.log('f1 args', args)
if (args.length >= arity) {
console.log('enough arguments')
return fn(...args)
} else {
console.log('need more arguments')
}
}
}
Обратите внимание, что я опять применил оператор spread. Так как args был у нас массивом аргументов, то чтобы его конвертировать обратно в аргументы через запятую - нам нужен spread.
То есть мы вызвали функцию fn, передали в нее аргументы и вернули результат.
Если мы сейчас изменим нашу функцию add и у нее будет 1 аргумент, то наше условие отработает, и в result мы получим ответ.
Теперь давайте вернем аргументы add обратно и допишем наш else.
Если у нас недостаточно аргументов, то мы хотим вернуть новую функцию, в которой мы тоже хотим узнать аргументы
var curry = function (fn) {
var arity = fn.length
return function f1(...args) {
console.log('f1 args', args)
if (args.length >= arity) {
console.log('enough arguments')
return fn(...args)
} else {
console.log('need more arguments')
return function f2(...moreArgs) {
console.log('f2', moreArgs)
}
}
}
}
Теперь давайте вызовем curriedAdd еще раз.
var result = curriedAdd(1)(2)
Если мы посмотрим в браузер, то у нас вывелось f2 с массивом, который содержит нашу двойку.
Обратите внимание, что сейчас нам доступно не только arity из первой функции, но и args из второй функции.
Поэтому мы можем сконкатить args и moreArgs, чтобы вызвать функцию f1 с новыми аргументами.
var curry = function (fn) {
var arity = fn.length
return function f1(...args) {
console.log('f1 args', args)
if (args.length >= arity) {
console.log('enough arguments')
return fn(...args)
} else {
console.log('need more arguments')
return function f2(...moreArgs) {
console.log('f2', moreArgs)
var newArgs = args.concat(moreArgs)
return f1(...newArgs)
}
}
}
}
То есть мы делаем новый массив из 1 и 2. И потом вызываем и возвращаем функцию f1, которую мы описали выше. То есть у нас получается рекурсия функции f1, которая будет идти, пока мы не получим достаточно аргументов.
Теперь наша функция curry может работать с любым количеством аргументов и принимать их любым образом.
Давайте попробуем передавать аргументы по-разному.
curriedAdd(1)(2)(3)
curriedAdd(1)(2, 3)
curriedAdd(1, 2, 3)
Еще раз по шагам, что мы делаем
Если у вас возникли какие-то вопросы или комментарии, пишите их прямо под этим видео.