Recomendações relacionadas: tutorial de javascript
apply(context,[arguments])
, call(context,param1,param2,...)
.Currying é uma técnica que transforma uma função que aceita múltiplos parâmetros em uma função que aceita um único parâmetro (o primeiro parâmetro da função original), e retorna uma nova função que aceita os parâmetros restantes e retorna um resultado.
Por exemplo, aqui está uma função add()
, que é uma função usada para processar a adição e soma dos parâmetros (param1, params2,...) que passamos para ela.
// Aqui está a primeira função `add(x, y)` com dois parâmetros `x`, `y` function add(x, y){ retornar x + y; } // Chame a função `add()` e forneça dois parâmetros `4` e `6` adicionar(4,6); //Simula a operação do computador, passa o primeiro parâmetro 4 no primeiro passo função adicionar(4, y){ retorne 4 + y; } //Simula a operação do computador, passa o primeiro parâmetro 6 no segundo passo função adicionar(4, 6){ retorne 4 + 6; }
Como seria se curríssemos a função add()
? Aqui está uma implementação simples:
// A função curried add() pode aceitar alguns parâmetros function add(x,y){ if (typeof y === 'indefinido') { função de retorno (nova){ retornar x + novo; } } // Retorno completo da aplicação x + y; } // Chamadas de teste console.log(typeof add(4)); console.log(add(4)(6)); // Você pode criar uma função de salvamento let saveAdd = add(4); console.log(saveAdd(6)); // 10
Como pode ser visto na função curried add()
simples acima, a função pode aceitar algumas funções e então retornar uma nova função para continuar processando as funções restantes.
Aqui criamos uma função de currying pública, para que não tenhamos que implementar o complexo processo de currying dentro dela toda vez que escrevemos uma função.
//Definir uma função createCurry function createCurry(fn){ var fatia = Array.prototype.slice, storage_args = slice.call(argumentos,1); função de retorno () { deixe new_args = slice.call (argumentos), args=armazenados_args.concat(novos_args); retornar fn.apply(null,args); }}
Na função de currying pública acima:
arguments
não é um array real, mas um objeto com um atributo length
, então pegamos emprestado o método slice
de Array.prototype
para nos ajudar a converter arguments
em um array real, para facilitar nossa melhor operação.createCurry
pela primeira vez, a variável stored_args
contém os parâmetros, exceto o primeiro parâmetro, porque o primeiro parâmetro é a função que precisamos curry.createCurry
, a variável new_args
obtém os parâmetros e os converte em um array.stored_args
por meio do encerramento e mescla o valor da variável new_args
em um novo array e o atribui à variável args
.fn.apply(null,args)
é chamado para executar a função curried.Agora vamos testar a função curried pública
// função ordinária add() função adicionar(x, y){ retornar x + y; } // Curry para obter uma nova função var newAdd = createCurry(add,4); console.log(newAdd(6)); //Outra maneira simples console.log(createCurry(add,4)(6));// 10
Claro, isso não se limita ao curry de dois parâmetros, mas também a vários parâmetros:
// Vários parâmetros A função comum function add (a,b,c,d){ retornar a + b + c + d; } // Curry a função para obter uma nova função, vários parâmetros podem ser divididos à vontade console.log(createCurry(add,4,5)(5,6)); // Curry em duas etapas let add_one = createCurry(add,5); console.log(add_one(5,5,5));// 20 deixe add_two = createCurry(add_one,4,6); console.log(add_two(6)); // 21Através
do exemplo acima, podemos encontrar uma limitação, ou seja, sejam dois parâmetros ou vários parâmetros, só pode ser executado em duas etapas, como a seguinte fórmula:
se quisermos ser mais flexíveis:
)
Após os exercícios acima, descobrimos que a função com curry que criamos tem certas limitações. Esperamos que a função possa ser executada em várias etapas:
// Crie uma função com curry que possa ser executada em várias etapas Função. , execute-o quando o número de parâmetros for atendido: // Fórmula da função: fn(x,y,z,w) ==> fn(x)(y)(z)(w); deixe criarCurry = (fn,...params)=> { deixe args = parsmos || let fnLen = fn.length; // Especifique o comprimento do parâmetro da função curried; retornar (...res)=> { // Obtém todos os parâmetros anteriores através da cadeia de escopo let allArgs = args.slice(0); // Copie profundamente os parâmetros args compartilhados pelos encerramentos para evitar o impacto de operações subsequentes (tipo de referência) allArgs.push(...res); if(allArgs.length <fnLen){ // Quando o número de parâmetros for menor que o comprimento do parâmetro da função original, chame a função createCurry recursivamente return createCurry.call(this,fn,...allArgs); }outro{ // Quando o número de parâmetros é atingido, aciona a execução da função return fn.apply(this,allArgs); } } } // Função comum function add(a,b,c,d){ com múltiplos parâmetros retornar a + b + c + d; } //Teste a função currying let curryAdd = createCurry(add,1); console.log(curryAdd(2)(3)(4)); //
Implementamos funções de curry flexíveis há mais de 10 anos, mas aqui encontramos outro problema:
curryAdd(add,1,2,3,4)()
;add()
original. Esta também é uma via, mas como estamos satisfazendo o número de parâmetros aqui, ainda lidamos com esta situação.Aqui só precisamos fazer um julgamento antes de retornar a função:
let createCurry = (fn,...params)=> { deixe args = parsmos || let fnLen = fn.length; // Especifique o comprimento do parâmetro da função curried; if(comprimento === _args.comprimento){ //Adicionar julgamento. Se o número de parâmetros pela primeira vez for suficiente, chame a função diretamente para obter o resultado return fn.apply(this,args); } retornar (...res)=> { deixe allArgs = args.slice(0); allArgs.push(...res); if(allArgs.length <fnLen){ retornar createCurry.call(this,fn,...allArgs); }outro{ return fn.apply(this,allArgs); } }}
A função acima pode ser considerada uma função curry flexível, mas não é muito flexível aqui porque não podemos controlar quando ela é executada. Contanto que o número de parâmetros seja suficiente, ela será executada automaticamente. O que devemos fazer se quisermos atingir um timing que possa controlar a sua execução?
Vamos explicar diretamente a fórmula da função aqui:
// Quando os parâmetros forem satisfeitos, chame a função let createCurry = (fn,...params)=> { deixe args = parsmos || let fnLen = fn.length; // Especifique o comprimento do parâmetro da função curried; //É claro que o julgamento aqui precisa ser comentado, caso contrário o resultado será executado diretamente quando o número de parâmetros for suficiente pela primeira vez //if(length === _args.length){ // Adicione julgamento. Se o número de parâmetros pela primeira vez for suficiente, chame a função diretamente para obter o resultado //return fn.apply(this,args); //} retornar (...res)=> { deixe allArgs = args.slice(0); allArgs.push(...res); // Aqui é avaliado se os parâmetros de entrada são maiores que 0. Se for maior que 0, é julgado se o número de parâmetros é suficiente. // && não pode ser usado aqui Se && for usado, o resultado será executado quando o número de parâmetros for suficiente. if(res.length > 0 || allArgs.length < fnLen){ retornar createCurry.call(this,fn,...allArgs); }outro{ return fn.apply(this,allArgs); } } } // Função comum function add(a,b,c,d){ com múltiplos parâmetros retornar a + b + c + d; } // Testa a função de curry controlável let curryAdd = createCurry(add,1); console.log(curryAdd(2)(3)(4)); console.log(curryAdd(2)(3)(4)()); console.log(curryAdd(2)(3)()); // Retorna NaN quando os parâmetros não são suficientes.Recomendações
relacionadas
: Tutorial de aprendizado de JavaScript.
preste atenção em php Outros artigos relacionados no site chinês!