Home  >  Article  >  Web Front-end  >  Let’s talk about JavaScript function currying

Let’s talk about JavaScript function currying

WBOY
WBOYforward
2022-03-04 18:16:101937browse

This article brings you relevant knowledge about javascript, which mainly introduces the related issues of function currying in JavaScript. Currying is to transform a function that accepts multiple parameters. It is a technique that accepts a single parameter and returns a new function that accepts the remaining parameters and returns the result. I hope it will be helpful to everyone.

Let’s talk about JavaScript function currying

Related recommendations: javascript tutorial

1. Briefly understand apply and call

  • call and apply both exist to change the context when a function is running. In other words, they are to change the pointer of this inside the function body.
  • call and apply have exactly the same function, but the way they accept parameters is different. call is actually a kind of syntactic sugar for apply.
  • Format: apply(context,[arguments]),call(context,param1,param2,...).

2. What is function currying?

Currying is to transform a function that accepts multiple parameters into a function that accepts a single parameter (the first parameter of the original function), and returns a new function that accepts the remaining parameters and returns the result. Technology.

For example, there is a add() function, which is a function used to process the addition and sum of the parameters (param1, params2,...) we pass to it. .

// 在这里第一个具有两个参数`x`、`y`的`add(x , y)`函数
function add(x , y){
	return x + y;
}

// 调用`add()`函数,并给定两个参数`4`和`6`
add(4,6);

// 模拟计算机操作,第一步 传入第一个参数 4
function add(4 , y){
	return 4 + y;
}

// 模拟计算机操作,第二步 传入第一个参数 6
function add(4 , 6){
	return 4 + 6;
}

What would it look like if we curried the add() function? Here is a simple implementation:

// 柯里化过的add()函数,可以接受部分参数
function add(x ,y){
	if (typeof y === 'undefined') {
		return function (newy){
			return x + newy;
		}
	}
	// 完整应用
	return x + y;
}

// 测试调用
console.log(typeof add(4)); // [Function]
console.log(add(4)(6)); // 10

// 可以创建保存函数
let saveAdd = add(4);
console.log(saveAdd(6)); // 10

As can be seen from the above simple curried add() function, the function can accept some functions and then return a new function to make it Continue with the remaining functions.

3. Write a public curried function

Here we create a public curried function, so that we don’t have to implement complex functions internally every time we write a function The currying process.

// 定义一个createCurry的函数function createCurry(fn){
	var slice = Array.prototype.slice,
	stored_args = slice.call(arguments,1);
	
	return function () {
		let new_args = slice.call(arguments),
		args = stored_args.concat(new_args);
		return fn.apply(null,args);
	}}

In the above public curried function:

  • arguments, is not a real array, just an array with lengthAttribute object, so we borrow the slice method from Array.prototype to help us convert arguments into a real array to facilitate our better operations .
  • When we call function createCurry for the first time, the variable stored_args holds the parameters except the first parameter, because the first parameter is We need curried functions.
  • When we execute the function returned in the createCurry function, the variable new_args gets the parameters and converts them into an array.
  • The function returned internally accesses the value stored in the variable stored_args through a closure and the value of the variable new_args is combined into a new array and assigned to the variable args.
  • Finally call the fn.apply(null,args) method to execute the curried function.

Now let’s test the public currying function

// 普通函数add()
function add(x , y){
	return x + y;
}

// 柯里化得到一个新的函数
var newAdd = createCurry(add,4);
console.log(newAdd(6)); // 10


//另一种简便方式
console.log(createCurry(add,4)(6));// 10

Of course, this is not limited to currying of two parameters, but can also be multiple Parameters:

// 多个参数的普通函数
function add(a,b,c,d){
	return 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
let add_two = createCurry(add_one,4,6);
console.log(add_two(6)); // 21

Through the above example, we can find a limitation, that is, whether it is two parameters or multiple parameters, it can only be executed in two steps, such as the following formula:

  • fn(x,y) ==> fn(x)(y);
  • fn(x,y,z,w) ==> fn(x)(y,z, w) || fn(x,y)(z,w)||…

If we want to be more flexible:

  • fn(x,y) = => fn(x)(y);
  • fn(x,y,z) ==> fn(x,y)(z) || fn(x)(y)(z) ;
  • fn(x,y,z,w) ==> fn(x,y)(z)(w) || fn(x)(y)(z)(w) || …;

How do we achieve it?

4. Create a flexible curried function

After the above exercises, we found that the curried function we created has certain limitations. We hope that the function can be executed in multiple steps:

// 创建一个可以多步执行的柯里化函数,当参数满足数量时就去执行它:
// 函数公式:fn(x,y,z,w) ==> fn(x)(y)(z)(w);
let createCurry = (fn,...params)=> {
	let args = parsms || [];
	let fnLen = fn.length; // 指定柯里化函数的参数长度
	
	return (...res)=> {
		// 通过作用域链获取上一次的所有参数
		let allArgs = args.slice(0);
		// 深度拷贝闭包共用的args参数,避免后续操作影响(引用类型)
		allArgs.push(...res);
		if(allArgs.length < fnLen){
		   // 当参数数量小于原函数的参数长度时,递归调用createCurry函数
		   return createCurry.call(this,fn,...allArgs);
		}else{
		  // 当参数数量满足时,触发函数执行
		  return fn.apply(this,allArgs);
		}
	}
}


// 多个参数的普通函数
function add(a,b,c,d){
	return a + b + c + d;
}

// 测试柯里化函数

let curryAdd = createCurry(add,1);
console.log(curryAdd(2)(3)(4)); // 10

We have implemented a flexible currying function above, but here we find another problem:

  • If I pass in all the parameters for the first time, but It does not return a result, but a function.
  • Only if we call the returned function once again can the result be returned: curryAdd(add,1,2,3,4)();
  • Some people may say that if To pass all parameters, just call the original add() function. This is also a way; but since we are here to meet the number of parameters, we still deal with this situation.

Here we only need to make a judgment before returning the function:

let createCurry = (fn,...params)=> {
	let args = parsms || [];
	let fnLen = fn.length; // 指定柯里化函数的参数长度
	
	if(length === _args.length){
	   // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果
           return fn.apply(this,args);
        }
	return (...res)=> {
		let allArgs = args.slice(0);
		allArgs.push(...res);
		if(allArgs.length < fnLen){
		   return createCurry.call(this,fn,...allArgs);
		}else{
		  return fn.apply(this,allArgs);
		}
	}}

The above can be regarded as completing a flexible currying function, but there is not yet The calculation is very flexible because we cannot control when it is executed. It will be executed automatically as long as the number of parameters is sufficient. What should we do if we want to achieve a timing that can control its execution?

5. Write a curried function with controllable execution time

Let’s directly explain the function formula here:

  • fn(a,b,c) ==> fn(a)(b)(c )();
  • fn(a,b,c) ==> fn(a);fn(b);fn(c );fn();
  • 当我们参数足够时它并不会执行,只有我们再次调用一次函数它才会执行并返回结果。在这里我们在以上例子中加一个小小的条件就可以实现。
  • // 当参数满足,再次执行时调用函数
    let createCurry = (fn,...params)=> {
    	let args = parsms || [];
    	let fnLen = fn.length; // 指定柯里化函数的参数长度
    	
    	//当然这里的判断需要注释掉,不然当它第一次参数数量足够时就直接执行结果了
    	//if(length === _args.length){
    	   // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果
               //return fn.apply(this,args);
            //}
    	return (...res)=> {
    		let allArgs = args.slice(0);
    		allArgs.push(...res);
    		// 在这里判断输入的参数是否大于0,如果大于0在判断参数数量是否足够,
    		// 这里不能用 && ,如果用&& 也是参数数量足够时就执行结果了。
    		if(res.length > 0 || allArgs.length < fnLen){
    		   return createCurry.call(this,fn,...allArgs);
    		}else{
    		  return fn.apply(this,allArgs);
    		}
    	}
    }
    
    
    // 多个参数的普通函数
    function add(a,b,c,d){
    	return a + b + c + d;
    }
    
    // 测试可控制的柯里化函数
    
    let curryAdd = createCurry(add,1);
    console.log(curryAdd(2)(3)(4)); // function
    console.log(curryAdd(2)(3)(4)()); // 10
    console.log(curryAdd(2)(3)()); // 当参数不足够时返回 NaN

    相关推荐:javascript学习教程

    The above is the detailed content of Let’s talk about JavaScript function currying. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete