Рекомендации по теме: руководство по JavaScript
apply(context,[arguments])
, call(context,param1,param2,...)
.Каррирование — это метод, который преобразует функцию, принимающую несколько параметров, в функцию, принимающую один параметр (первый параметр исходной функции), и возвращает новую функцию, которая принимает остальные параметры и возвращает результат.
Например, вот функция add()
, которая используется для обработки сложения и суммы параметров (param1, params2,...), которые мы ей передаем.
// Вот первая функция `add(x, y)` с двумя параметрами `x`, `y` function add(x, y){ вернуть х + у; } // Вызываем функцию `add()` и передаем два параметра `4` и `6` добавить (4,6); // Имитируем работу компьютера, передаем первый параметр 4 на первом шаге функция add(4, y){ вернуть 4 + у; } // Имитируем работу компьютера, передаем первый параметр 6 на втором шаге функция добавить(4, 6){ вернуть 4 + 6; }
Как бы это выглядело, если бы мы каррировали функцию add()
? Вот простая реализация:
// Каррированная функция add() может принимать некоторые параметры function add(x,y){ if (typeof y === 'не определено') { функция возврата (новая){ вернуть х + новый; } } // Полный возврат приложения x + y; } // Тестовые вызовы console.log(typeof add(4)); // [Функция] console.log(add(4)(6)); // 10; // Вы можете создать функцию сохранения let saveAdd = add(4); console.log(saveAdd(6)); // 10
Как видно из приведенной выше простой каррированной функции add()
, функция может принимать некоторые функции, а затем возвращать новую функцию для продолжения обработки оставшихся функций.
Здесь мы создаем публичную функцию каррирования, чтобы нам не приходилось реализовывать внутри нее сложный процесс каррирования каждый раз, когда мы пишем функцию.
//Определяем функцию createCurry function createCurry(fn){ вар срез = Array.prototype.slice, хранимые_арги = срез.вызов(аргументы,1); функция возврата () { пусть new_args = срез.call(аргументы), args =store_args.concat(new_args); вернуть fn.apply(null,args); }}
В приведенной выше публичной функции каррирования:
arguments
— это не настоящий массив, а объект с атрибутом length
, поэтому мы заимствуем метод slice
из Array.prototype
который поможет нам преобразовать arguments
в реальный массив, чтобы облегчить нашу работу.createCurry
в первый раз, переменная stored_args
содержит параметры, кроме первого параметра, поскольку первый параметр — это функция, которую нам нужно каррировать.createCurry
, переменная new_args
получает параметры и преобразует их в массив.stored_args
через замыкание, объединяет значение переменной new_args
в новый массив и присваивает его переменной args
.fn.apply(null,args)
для выполнения каррированной функции.Теперь давайте проверим публичную каррированную функцию
// обычную функцию add(). функция add(x, y){ вернуть х + у; } // Карри для получения новой функции var newAdd = createCurry(add,4); console.log(newAdd(6)); // 10 //Еще один простой способ console.log(createCurry(add,4)(6));// 10
Конечно, это не ограничивается каррированием двух параметров, но также и нескольких параметров:
// Несколько параметров Обычная функция функция add (а, б, в, г) { вернуть a + b + c + d; } // Карри функцию, чтобы получить новую функцию, несколько параметров можно разделить по желанию console.log(createCurry(add,4,5)(5,6)); // 20 // Двухэтапное карри let add_one = createCurry(add,5); console.log(add_one(5,5,5));// 20 пусть add_two = createCurry(add_one,4,6); console.log(add_two(6)); // 21В
приведенном выше примере мы можем найти ограничение, то есть, независимо от того, два параметра или несколько параметров, его можно выполнить только в два этапа, как, например, следующая формула:
если мы хотим быть более гибкими:
Как это реализовать?
После приведенных выше упражнений мы обнаружили, что созданная нами каррированная функция имеет определенные ограничения. Мы надеемся, что функцию можно выполнить в несколько шагов:
// Создаем каррированную функцию, которая может выполняться в несколько шагов. Функция. , выполните его, когда будет достигнуто необходимое количество параметров: // Формула функции: fn(x,y,z,w) ==> fn(x)(y)(z)(w); let createCurry = (fn,...params)=> { пусть args = parsms []; let fnLen = fn.length // Укажите длину параметра каррированной функции; return (...res)=> { // Получаем все предыдущие параметры через цепочку областей let allArgs = args.slice(0); // Глубоко копируем параметры args, общие для замыканий, чтобы избежать влияния последующих операций (ссылочный тип) allArgs.push(...res); если (allArgs.length < fnLen) { // Когда количество параметров меньше длины параметра исходной функции, рекурсивно вызываем функцию createCurry return createCurry.call(this,fn,...allArgs); }еще{ // Когда количество параметров достигнуто, выполнение триггерной функции return fn.apply(this,allArgs); } } } // Обычная функция function add(a,b,c,d){ с несколькими параметрами вернуть a + b + c + d; } //Проверка функции каррирования let curryAdd = createCurry(add,1); console.log(curryAdd(2)(3)(4)); //
Мы реализуем гибкие функции каррирования уже более 10 лет, но здесь мы обнаруживаем другую проблему:
curryAdd(add,1,2,3,4)()
;add()
; Это тоже один из способов; но поскольку мы удовлетворяем здесь количеству параметров, мы все равно имеем дело с этой ситуацией.Здесь нам нужно только принять решение, прежде чем возвращать функцию:
let createCurry = (fn,...params)=> { пусть args = parsms []; let fnLen = fn.length // Укажите длину параметра каррированной функции; если (длина === _args.length) { //Добавить решение. Если количества параметров в первый раз достаточно, вызовите функцию напрямую, чтобы получить результат return fn.apply(this,args); } return (...res)=> { пусть allArgs = args.slice(0); allArgs.push(...res); если (allArgs.length < fnLen) { return createCurry.call(this,fn,...allArgs); }еще{ вернуть fn.apply(this,allArgs); } }}
Вышеупомянутую функцию можно рассматривать как гибкую каррированную функцию, но здесь она не очень гибкая, поскольку мы не можем контролировать, когда она будет выполняться. Пока количество параметров достаточно, она будет выполняться автоматически. Что нам следует делать, если мы хотим добиться времени, позволяющего контролировать его выполнение?
Давайте прямо объясним формулу функции:
// Когда параметры удовлетворяются, вызываем функцию let createCurry = (fn,...params)=> { пусть args = parsms []; let fnLen = fn.length // Укажите длину параметра каррированной функции; //Конечно, решение здесь необходимо закомментировать, иначе результат будет выполнен напрямую, когда количество параметров будет достаточным для первого раза //if(length === _args.length){ // Добавляем решение. Если количества параметров в первый раз достаточно, вызываем функцию напрямую, чтобы получить результат //return fn.apply(this,args); //} return (...res)=> { пусть allArgs = args.slice(0); allArgs.push(...res); // Здесь оценивается, больше ли входные параметры 0. Если оно больше 0, оценивается, достаточно ли количество параметров. // Здесь нельзя использовать &&. Если используется &&, результат будет выполнен, когда количество параметров будет достаточным. if(res.length > 0 || allArgs.length < fnLen){ return createCurry.call(this,fn,...allArgs); }еще{ вернуть fn.apply(this,allArgs); } } } // Обычная функция function add(a,b,c,d){ с несколькими параметрами вернуть a + b + c + d; } // Тестирование управляемой функции каррирования let curryAdd = createCurry(add,1); console.log(curryAdd(2)(3)(4)); // функция console.log(curryAdd(2)(3)(4)()); // 10 console.log(curryAdd(2)(3)()); // Возвращает NaN, если параметров недостаточно.
Рекомендации по теме: Учебное пособие по JavaScript.
Выше рассказывается о деталях каррирования функций JavaScript. пожалуйста, обратите внимание на php Другие статьи по теме на китайском сайте!