JavaScript 함수 커링에 대해 이야기해 보겠습니다.
이 글에서는 JavaScript의 함수 커링과 관련된 문제를 주로 소개하는 javascript에 대한 관련 지식을 제공합니다. 커링은 여러 매개변수를 허용하는 함수를 단일 매개변수를 허용하는 함수로 변환하고 이를 반환하는 새로운 함수입니다. 나머지 매개변수를 수락하고 결과를 반환합니다. 이것이 모든 사람에게 도움이 되기를 바랍니다.
관련 추천: javascript tutorial
1. Apply와 call
- call을 간단히 이해하고, Apply와 Apply 둘 다 존재하면 특정 기능이 실행될 때 컨텍스트를 변경합니다. 함수 본문 내부의 this 포인터입니다.
- call과 Apply는 기능은 완전히 동일하지만 매개변수를 받아들이는 방식이 다릅니다. call은 실제로 적용을 위한 일종의 구문 설탕입니다.
- 형식:
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) ==> 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);
- fn(x,y,z,w) ==> fn(x,y)(z)(w) || fn(x)(y)(z)(w) || …;
我们该怎么实现呢?
四、创建一个灵活的柯里化函数
经过以上练习,我们发现我们创建的柯里化函数存在一定局限性,我们希望函数可以分为多步执行:
// 创建一个可以多步执行的柯里化函数,当参数满足数量时就去执行它: // 函数公式: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
以上我们已经实现了灵活的柯里化函数,但是这里我们又发现了一个问题:
- 如果我第一次就把参数全部传入,但是它并没有返回结果,而是一个函数(function)。
- 只有我们再次将返回的函数调用一次才能返回结果:
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);
}
}}
로그인 후 복사
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. 실행 시간을 제어할 수 있는 커리 함수를 작성하세요🎜🎜여기서 함수 공식을 직접 설명해 보겠습니다.🎜
- 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学习教程
위 내용은 JavaScript 함수 커링에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











WebSocket 및 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 소개: 지속적인 기술 개발로 음성 인식 기술은 인공 지능 분야의 중요한 부분이 되었습니다. WebSocket과 JavaScript를 기반으로 한 온라인 음성 인식 시스템은 낮은 대기 시간, 실시간, 크로스 플랫폼이라는 특징을 갖고 있으며 널리 사용되는 솔루션이 되었습니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법을 소개합니다.

WebSocket과 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 서론: 인터넷 기술의 급속한 발전과 함께 실시간 모니터링 시스템이 다양한 분야에서 널리 활용되고 있다. 실시간 모니터링을 구현하는 핵심 기술 중 하나는 WebSocket과 JavaScript의 조합입니다. 이 기사에서는 실시간 모니터링 시스템에서 WebSocket 및 JavaScript의 적용을 소개하고 코드 예제를 제공하며 구현 원칙을 자세히 설명합니다. 1. 웹소켓 기술

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 오늘날의 디지털 시대에는 점점 더 많은 기업과 서비스에서 온라인 예약 기능을 제공해야 합니다. 효율적인 실시간 온라인 예약 시스템을 구현하는 것이 중요합니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. WebSocket이란 무엇입니까? WebSocket은 단일 TCP 연결의 전이중 방식입니다.

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 소개: 인터넷의 대중화와 기술의 발전으로 점점 더 많은 레스토랑에서 온라인 주문 서비스를 제공하기 시작했습니다. 실시간 온라인 주문 시스템을 구현하기 위해 JavaScript 및 WebSocket 기술을 사용할 수 있습니다. WebSocket은 TCP 프로토콜을 기반으로 하는 전이중 통신 프로토콜로 클라이언트와 서버 간의 실시간 양방향 통신을 실현할 수 있습니다. 실시간 온라인 주문 시스템에서는 사용자가 요리를 선택하고 주문을 하면

JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

JavaScript 및 WebSocket: 효율적인 실시간 일기 예보 시스템 구축 소개: 오늘날 일기 예보의 정확성은 일상 생활과 의사 결정에 매우 중요합니다. 기술이 발전함에 따라 우리는 날씨 데이터를 실시간으로 획득함으로써 보다 정확하고 신뢰할 수 있는 일기예보를 제공할 수 있습니다. 이 기사에서는 JavaScript 및 WebSocket 기술을 사용하여 효율적인 실시간 일기 예보 시스템을 구축하는 방법을 알아봅니다. 이 문서에서는 특정 코드 예제를 통해 구현 프로세스를 보여줍니다. 우리

JavaScript에서 HTTP 상태 코드를 얻는 방법 소개: 프런트 엔드 개발에서 우리는 종종 백엔드 인터페이스와의 상호 작용을 처리해야 하며 HTTP 상태 코드는 매우 중요한 부분입니다. HTTP 상태 코드를 이해하고 얻는 것은 인터페이스에서 반환된 데이터를 더 잘 처리하는 데 도움이 됩니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. HTTP 상태 코드란 무엇입니까? HTTP 상태 코드는 브라우저가 서버에 요청을 시작할 때 서비스가

사용법: JavaScript에서 insertBefore() 메서드는 DOM 트리에 새 노드를 삽입하는 데 사용됩니다. 이 방법에는 삽입할 새 노드와 참조 노드(즉, 새 노드가 삽입될 노드)라는 두 가지 매개 변수가 필요합니다.
