이 기사는 JS의 절묘한 자동 커링 방법을 자세히 분석하고 코드 예제를 통해 프로세스와 원리를 분석하므로 도움이 되길 바랍니다.
커링이란 무엇인가요?
컴퓨터 과학에서 커링은 여러 매개변수를 받는 함수를 단일 매개변수(원래 함수의 첫 번째 매개변수)를 받는 함수로 변환하고, 나머지 매개변수를 받아 결과를 반환하는 함수를 반환하는 것입니다. 기능 기술. 이 기술은 Moses Schnfinkel과 Gottlob Frege가 발명했지만 논리학자 Haskell Curry의 이름을 따서 Christopher Strachey가 명명했습니다.
이론이 압도적인 것 같나요? 중요하지 않습니다. 먼저 코드를 살펴보겠습니다.
Curriization application
목록의 각 요소에 하나를 추가하는 등 목록 요소에 대한 일부 처리를 수행하는 함수를 구현해야 한다고 가정해 보겠습니다. 생각하기 쉽습니다:
const list = [0, 1, 2, 3]; list.map(elem => elem + 1);
쉽죠? 2개를 더 추가하고 싶다면 어떻게 해야 할까요?
const list = [0, 1, 2, 3]; list.map(elem => elem + 1); list.map(elem => elem + 2);
좀 비효율적인 것 같은데요. 처리 기능을 캡슐화할 수 있나요?
하지만 map의 콜백 함수는 현재 요소 elem만 매개변수로 받아들입니다. 이를 캡슐화할 방법은 없는 것 같습니다...
부분적으로 구성된 함수를 얻을 수 있으면 좋겠다고 생각할 수도 있습니다. , 예:
// plus返回部分配置好的函数 const plus1 = plus(1); const plus2 = plus(2); plus1(5); // => 6 plus2(7); // => 9
다음과 같은 함수를 map에 전달합니다.
const list = [0, 1, 2, 3]; list.map(plus1); // => [1, 2, 3, 4] list.map(plus2); // => [2, 3, 4, 5]
멋지지 않나요? 이렇게 하면 아무리 추가해도 list.map(plus(x))만 있으면 캡슐화를 완벽하게 구현하고 가독성이 크게 향상됩니다!
하지만 질문이 생깁니다. 이러한 플러스 기능을 어떻게 구현하나요?
여기서 커링이 유용합니다:
커링 함수
// 原始的加法函数 function origPlus(a, b) { return a + b; } // 柯里化后的plus函数 function plus(a) { return function(b) { return a + b; } } // ES6写法 const plus = a => b => a + b;
보시다시피 커링 플러스 함수는 먼저 매개변수 a를 받은 다음 매개변수 b 함수를 반환합니다. function은 상위 함수의 매개변수 a에 액세스할 수 있습니다. 예를 들어, const plus2 = plus(2)는 function plus2(b) { return 2 + b }와 동일할 수 있으므로 부분 구성이 가능합니다.
일반인의 관점에서 커링은 다중 매개변수 함수를 부분적으로 구성하는 프로세스이며, 각 단계는 단일 매개변수를 허용하는 부분적으로 구성된 함수를 반환합니다. 극단적인 경우에는 여러 번 추가하는 등 기능을 여러 번 부분적으로 구성해야 할 수도 있습니다.
multiPlus(1)(2)(3); // => 6
이런 작성 방식이 이상해 보이죠? 하지만 JS 함수형 프로그래밍의 큰 함정에 빠지면 이것이 표준이 될 것입니다.
JS에서 자동 커링을 절묘하게 구현
커링은 함수형 프로그래밍에서 매우 중요한 부분입니다(예: 하스켈). 기본적으로 함수가 자동으로 커링됩니다. 하지만 JS에서는 이를 수행하지 않으므로 자동 커링 기능을 직접 구현해야 합니다.
먼저 코드를 입력하세요:
// ES5 function curry(fn) { function _c(restNum, argsList) { return restNum === 0 ? fn.apply(null, argsList) : function(x) { return _c(restNum - 1, argsList.concat(x)); }; } return _c(fn.length, []); } // ES6 const curry = fn => { const _c = (restNum, argsList) => restNum === 0 ? fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []); } /***************** 使用 *********************/ var plus = curry(function(a, b) { return a + b; }); // ES6 const plus = curry((a, b) => a + b); plus(2)(4); // => 6
이렇게 하면 자동 커링이 이루어집니다!
무슨 일이 일어났는지 이해할 수 있다면 축하합니다! 모두가 당신을 부르는 상사는 당신입니다! , 좋아요를 남기고 기능적 경력을 시작하세요. (재미있습니다
무슨 일이 일어나고 있는지 이해하지 못하더라도 걱정하지 마세요. 지금 아이디어를 정리하는 데 도움을 드릴 것입니다.
요구 사항 분석
카레가 필요해요 커리할 함수를 매개변수로 받아들이고 매개변수를 받은 함수를 반환하는 함수입니다. 받은 매개변수가 목록에 배치되면 원래 함수가 실행되고 결과가 반환됩니다.
구현 방법function(x) { return _c(restNum - 1, argsList.concat(x)); }
function curry(fn) { function _c(restNum, argsList) { return restNum === 0 ? fn.apply(null, argsList) : function(x) { return _c(restNum - 1, argsList.concat(x)); }; } return _c(fn.length, []); // 递归开始 }
// ES6 const curry = fn => { const _c = (restNum, argsList) => restNum === 0 ? fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []); }
다른 방법과의 비교
function curry(fn) { const len = fn.length; return function judge(...args1) { return args1.length >= len ? fn(...args1): function(...args2) { return judge(...[...args1, ...args2]); } } } // 使用箭头函数 const curry = fn => { const len = fn.length; const judge = (...args1) => args1.length >= len ? fn(...args1) : (...args2) => judge(...[...args1, ...args2]); return judge; }
性能稍差一点。
性能问题
做个测试:
console.time("curry"); const plus = curry((a, b, c, d, e) => a + b + c + d + e); plus(1)(2)(3)(4)(5); console.timeEnd("curry");
在我的电脑(Manjaro Linux,Intel Xeon E5 2665,32GB DDR3 四通道1333Mhz,Node.js 9.2.0)上:
本篇提到的方法耗时约 0.325ms
其他方法的耗时约 0.345ms
差的这一点猜测是闭包的原因。由于闭包的访问比较耗性能,而这种方式形成了两个闭包:fn 和 len,前面提到的方法只形成了 fn 一个闭包,所以造成了这一微小的差距。
相关推荐:
위 내용은 JS에서 절묘한 자동 커링 기능을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!