
Recomendaciones relacionadas: tutorial de javascript
apply(context,[arguments]) , call(context,param1,param2,...) .Currying es una técnica que transforma una función que acepta múltiples parámetros en una función que acepta un solo parámetro (el primer parámetro de la función original) y devuelve una nueva función que acepta los parámetros restantes y devuelve un resultado.
Por ejemplo, aquí hay una función add() , que es una función utilizada para procesar la suma y suma de los parámetros (param1, params2,...) que le pasamos.
// Aquí está la primera función `add(x, y)` con dos parámetros `x`, función `y` add(x, y){
devolver x + y;
}
// Llama a la función `add()` y proporciona dos parámetros `4` y `6`
agregar(4,6);
// Simula el funcionamiento de la computadora, pasa el primer parámetro 4 en el primer paso
función agregar(4, y){
devolver 4 + y;
}
// Simula el funcionamiento de la computadora, pasa el primer parámetro 6 en el segundo paso
función agregar(4, 6){
devolver 4 + 6;
} ¿Cómo se vería si aplicamos curry a la función add() ? Aquí hay una implementación simple:
// La función add() al curry puede aceptar algunos parámetros function add(x,y){
if (tipo de y === 'indefinido') {
función de retorno (nueva) {
devolver x + nuevo;
}
}
// retorno de la aplicación completa x + y;
}
// Llamadas de prueba console.log(typeof add(4)); // [Función]
consola.log(add(4)(6)); // 10
// Puedes crear una función para guardar let saveAdd = add(4);
console.log(saveAdd(6)); // 10 Como se puede ver en la función add() simple al curry anterior, la función puede aceptar algunas funciones y luego devolver una nueva función para continuar procesando las funciones restantes.
Aquí creamos una función de curry pública, para que no tengamos que implementar el complejo proceso de curry dentro de ella cada vez que escribimos una función.
//Definir una función createCurry function createCurry(fn){
var segmento = Array.prototype.slice,
argumentos_almacenados = segmento.call(argumentos,1);
función de retorno () {
let new_args = slice.call(argumentos),
args = argumentos_almacenados.concat(nuevos_args);
devolver fn.apply(null,args);
}} En la función de curry pública anterior:
arguments no son una matriz real, sino un objeto con un atributo length , por lo que tomamos prestado el método slice de Array.prototype para ayudarnos a convertir arguments en una matriz real, para facilitar nuestra mejor operación.createCurry por primera vez, la variable stored_args contiene los parámetros excepto el primer parámetro, porque el primer parámetro es la función que necesitamos curry.createCurry , la variable new_args obtiene los parámetros y los convierte en una matriz.stored_args a través del cierre y fusiona el valor de la variable new_args en una nueva matriz y lo asigna a la variable args .fn.apply(null,args) para ejecutar la función curry.Ahora probemos la función pública de curry
// función ordinaria add()
función agregar(x, y){
devolver x + y;
}
// Curry para obtener una nueva función var newAdd = createCurry(add,4);
console.log(newAdd(6)); // 10
//Otra forma sencilla console.log(createCurry(add,4)(6));// 10 Por supuesto, esto no se limita a la curry de dos parámetros, sino también de múltiples parámetros:
// Múltiples parámetros La función ordinaria function add (a,b,c,d){
devolver a + b + c + d;
}
// Curra la función para obtener una nueva función, se pueden dividir múltiples parámetros a voluntad console.log(createCurry(add,4,5)(5,6));
// Curry de dos pasos let add_one = createCurry(add,5);
console.log(add_one(5,5,5));// 20
let add_two = createCurry(add_one,4,6);
console.log(add_two(6)); // 21 A través del ejemplo anterior, podemos encontrar una limitación, es decir, ya sean dos parámetros o múltiples parámetros, solo se puede ejecutar en dos pasos, como la siguiente fórmula:
si queremos ser más flexibles:
¿Cómo lo implementamos?
Después de los ejercicios anteriores, descubrimos que la función de curry que creamos tiene ciertas limitaciones. Esperamos que la función se pueda ejecutar en varios pasos:
// Cree una función de curry que se pueda ejecutar en varios pasos. , ejecútelo cuando se cumpla el número de parámetros:
// Fórmula de función: fn(x,y,z,w) ==> fn(x)(y)(z)(w);
let createCurry = (fn,...params)=> {
let args = parsmos ||
let fnLen = fn.length // Especifica la longitud del parámetro de la función al curry;
retorno (...res)=> {
// Obtiene todos los parámetros anteriores a través de la cadena de alcance let allArgs = args.slice(0);
// Copia en profundidad los parámetros args compartidos por los cierres para evitar el impacto de operaciones posteriores (tipo de referencia)
allArgs.push(...res);
if(allArgs.length < fnLen){
// Cuando el número de parámetros es menor que la longitud del parámetro de la función original, llama a la función createCurry de forma recursiva return createCurry.call(this,fn,...allArgs);
}demás{
// Cuando se alcanza el número de parámetros, activa la ejecución de la función return fn.apply(this,allArgs);
}
}
}
// Función ordinaria función add(a,b,c,d){ con múltiples parámetros
devolver a + b + c + d;
}
//Prueba la función de curry let curryAdd = createCurry(add,1);
console.log(curryAdd(2)(3)(4)); // Hemos implementado funciones de curry flexibles durante más de 10 años, pero aquí encontramos otro problema:
curryAdd(add,1,2,3,4)() ;add() original. Esto también es unidireccional; pero dado que aquí satisfacemos la cantidad de parámetros, todavía nos ocupamos de esta situación.Aquí solo necesitamos hacer un juicio antes de devolver la función:
let createCurry = (fn,...params)=> {
let args = parsmos ||
let fnLen = fn.length // Especifica la longitud del parámetro de la función al curry;
si(longitud === _args.length){
//Agregar juicio. Si la cantidad de parámetros por primera vez es suficiente, llame a la función directamente para obtener el resultado return fn.apply(this,args);
}
retorno (...res)=> {
let allArgs = args.slice(0);
allArgs.push(...res);
if(allArgs.length < fnLen){
return createCurry.call(this,fn,...allArgs);
}demás{
return fn.apply(this,allArgs);
}
}} Lo anterior puede considerarse como una función de curry flexible, pero aquí no es muy flexible porque no podemos controlar cuándo se ejecuta. Siempre que la cantidad de parámetros sea suficiente, se ejecutará automáticamente. ¿Qué debemos hacer si queremos conseguir un timing que pueda controlar su ejecución?
Expliquemos directamente la fórmula de la función aquí:
// Cuando se cumplan los parámetros, llame a la función let createCurry = (fn,...params)=> {
let args = parsmos ||
let fnLen = fn.length // Especifica la longitud del parámetro de la función al curry;
// Por supuesto, el juicio aquí debe comentarse; de lo contrario, el resultado se ejecutará directamente cuando el número de parámetros sea suficiente por primera vez //if(length === _args.length){
// Agregue juicio. Si la cantidad de parámetros por primera vez es suficiente, llame a la función directamente para obtener el resultado //return fn.apply(this,args);
//}
retorno (...res)=> {
let allArgs = args.slice(0);
allArgs.push(...res);
// Aquí se juzga si los parámetros de entrada son mayores que 0. Si es mayor que 0, se juzga si el número de parámetros es suficiente.
// && no se puede utilizar aquí. Si se utiliza &&, el resultado se ejecutará cuando el número de parámetros sea suficiente.
if(res.length > 0 || allArgs.length < fnLen){
return createCurry.call(this,fn,...allArgs);
}demás{
return fn.apply(this,allArgs);
}
}
}
// Función ordinaria función add(a,b,c,d){ con múltiples parámetros
devolver a + b + c + d;
}
// Pruebe la función de curry controlable let curryAdd = createCurry(add,1);
console.log(curryAdd(2)(3)(4) // función
console.log(curryAdd(2)(3)(4)()); // 10
console.log(curryAdd(2)(3)()); // Devuelve NaN cuando los parámetros no son suficientes. Recomendaciones relacionadas: Tutorial de aprendizaje de JavaScript
Lo anterior es para hablar sobre los detalles de la función curry de JavaScript. preste atención a php ¡Otros artículos relacionados en el sitio web chino!