이 글에서는 JavaScript의 함수 커링과 관련된 문제를 주로 소개하는 javascript에 대한 관련 지식을 제공합니다. 커링은 여러 매개변수를 허용하는 함수를 단일 매개변수를 허용하는 함수로 변환하고 이를 반환하는 새로운 함수입니다. 나머지 매개변수를 수락하고 결과를 반환합니다. 이것이 모든 사람에게 도움이 되기를 바랍니다.
관련 추천: javascript tutorial
apply(context,[인수])
, call(context,param1,param2,...)
. apply(context,[arguments])
,call(context,param1,param2,...)
。柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
在这里举个例子,有一个add()
函数,它是用来处理我们传给它的参数(param1,params2,…)相加求和的一个函数。
// 在这里第一个具有两个参数`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; }
如果我们将add()
函数柯里化,是什么样子呢?在这里简单的实现一下:
// 柯里化过的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
从以上简单柯里化的add()
函数可以看出,函数可以接受部分函数,然后返回一个新的函数,使其继续处理剩下的函数。
在这里我们创建一个公共的柯里化函数,那样我们就不必每次写一个函数都要在其内部实现复杂的柯里化过程。
// 定义一个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); }}
在以上公共的柯里化函数中:
arguments
,并不是一个真的数组,只是一个具有length
属性的对象,所以我们从Array.prototype
中借用slice
方法帮我们把arguments
转为一个真正的数组,方便我们更好的操作。createCurry
的时候,其中变量stored_args
是保持了除去第一个参数以外的参数,因为第一个参数是我们需要柯里化的函数。createCurry
函数中返回的函数时,变量new_args
获取参数并转为数组。stored_args
中存储的值和变量new_args
的值合并为一个新的数组,并赋值给变量args
。fn.apply(null,args)
方法,执行被柯里化的函数。现在我们来测试公共的柯里化函数
// 普通函数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
当然这里并不局限于两个参数的柯里化,也可以多个参数:
// 多个参数的普通函数 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
通过以上的例子,我们可以发现一个局限,那就是不管是两个参数还是多个参数,它只能分两步执行,如以下公式:
如果我们想更灵活一点:
我们该怎么实现呢?
经过以上练习,我们发现我们创建的柯里化函数存在一定局限性,我们希望函数可以分为多步执行:
// 创建一个可以多步执行的柯里化函数,当参数满足数量时就去执行它: // 函数公式: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
以上我们已经实现了灵活的柯里化函数,但是这里我们又发现了一个问题:
curryAdd(add,1,2,3,4)()
;add()
add()
함수가 있는데, 이는 우리가 전달하는 매개변수(param1, params2,...)의 더하기와 합을 처리하는 데 사용되는 함수입니다. 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); } }}
add()
함수를 커리하면 어떤 모습일까요? 다음은 간단한 구현입니다. // 当参数满足,再次执行时调用函数 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위의 간단한 카레
add()
함수에서 볼 수 있듯이 이 함수는 일부 함수를 수락한 다음 새 함수를 반환하여 해당 작업을 계속 처리할 수 있습니다. 나머지 기능은 아래에 있습니다. 🎜🎜3. 공개 커링 함수 작성🎜🎜여기에서는 함수를 작성할 때마다 내부에 복잡한 커링 프로세스를 구현할 필요가 없도록 공개 커링 함수를 만듭니다. 🎜rrreee🎜위의 공개 카레 함수에서: 🎜🎜🎜arguments
는 실제 배열이 아니고 단지 length
속성이 있는 객체이므로 부터 시작합니다. Array.prototype
은 slice
메소드를 빌려 인수
를 실제 배열로 변환하여 더 나은 작업을 수행할 수 있도록 도와줍니다. 🎜🎜 createCurry
함수를 처음 호출할 때 stored_args
변수는 첫 번째 매개변수를 제외한 매개변수를 보유합니다. 첫 번째 매개변수가 Curried 함수에 필요한 것이기 때문입니다. 🎜🎜 createCurry
함수에서 반환된 함수를 실행하면 new_args
변수가 매개변수를 가져와서 배열로 변환합니다. 🎜🎜반환된 함수는 클로저를 통해 내부적으로 stored_args
변수에 저장된 값에 액세스하고 new_args
변수의 값을 새 배열로 병합하여 < 코드>인수. 🎜🎜마지막으로 fn.apply(null,args)
메서드를 호출하여 카레 함수를 실행합니다. 🎜🎜🎜이제 공개 커링 기능을 테스트해 보겠습니다.🎜rrreee🎜물론 이는 두 매개변수의 커링에 국한되지 않고 여러 매개변수를 가질 수도 있습니다. 🎜rrreee🎜위의 예를 통해 다음을 수행할 수 있습니다. 즉, 매개변수가 두 개이든 여러 개이든 상관없이 다음 공식과 같이 두 단계로만 실행할 수 있습니다. 🎜🎜🎜fn(x,y) ==> );🎜🎜fn(x,y,z,w) ==> fn(x)(y,z,w) || fn(x,y)(z,w)||…🎜🎜🎜 더 유연해지고 싶다면: 🎜🎜🎜fn(x,y) ==> fn(x)(y);🎜🎜fn(x,y,z) ==> | | fn(x)(y)(z);🎜🎜fn(x,y,z,w) ==>fn(x,y)(z)(w) || ( z)(w) || …;🎜🎜🎜어떻게 구현하나요? 🎜🎜4. 유연한 카레 함수 만들기🎜🎜위의 연습을 통해 우리가 만든 카레 함수에 특정 제한이 있음을 발견했습니다. 우리는 이 함수가 여러 단계로 실행될 수 있기를 바랍니다. 🎜rrreee🎜우리는 위의 유연한 카레를 달성했습니다. 함수인데 여기서 또 다른 문제를 발견합니다. 🎜🎜🎜모든 매개변수를 처음으로 전달하면 결과가 반환되지 않고 함수가 반환됩니다. 🎜🎜반환된 함수를 다시 한 번 호출하는 경우에만 결과가 반환될 수 있습니다: curryAdd(add,1,2,3,4)()
;🎜🎜어떤 사람들은 모든 매개변수가 다음과 같다고 말할 수도 있습니다. 전달되면 그냥 호출하면 됩니다. 원래 add()
함수로 충분하며 이 역시 메서드이지만 여기에서 매개변수 수를 충족하므로 이 상황을 계속 처리합니다. 🎜🎜🎜여기서는 함수를 반환하기 전에 판단만 하면 됩니다. 🎜rrreee🎜위는 유연한 카레 함수를 완성한 것으로 간주할 수 있지만 여기서는 제어할 수 없기 때문에 그다지 유연하지 않습니다. 매개변수 수가 충분하면 자동으로 실행됩니다. 실행을 제어할 수 있는 타이밍을 구현하려면 어떻게 해야 합니까? 🎜🎜5. 실행 시간을 제어할 수 있는 커리 함수를 작성하세요🎜🎜여기서 함수 공식을 직접 설명해 보겠습니다.🎜
// 当参数满足,再次执行时调用函数 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学习教程
위 내용은 JavaScript 함수 커링에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!