카레의 유래는 수학자 하스켈 커리(프로그래밍 언어 하스켈도 그의 이름을 따서 명명됨)에서 유래되었습니다.
커링은 일반적으로 부분 평가라고도 합니다. 각 매개 변수가 전달된 후 매개 변수가 부분적으로 적용되고 더 구체적인 함수가 반환되어 나머지 매개 변수를 중첩할 수 있다는 의미입니다. 이 함수는 최종 결과가 반환될 때까지 일부 매개변수를 허용합니다.
따라서 커링 과정은 매개변수를 점진적으로 전달하고, 함수의 적용 범위를 점차 좁혀 문제를 점차 해결해 나가는 과정입니다.
합산 함수 커링
단계별 평가에 따라 간단한 예시를 살펴보겠습니다
var concat3Words = function (a, b, c) { return a+b+c; }; var concat3WordsCurrying = function(a) { return function (b) { return function (c) { return a+b+c; }; }; }; console.log(concat3Words("foo ","bar ","baza")); // foo bar baza console.log(concat3WordsCurrying("foo ")); // [Function] console.log(concat3WordsCurrying("foo ")("bar ")("baza")); // foo bar baza
보시다시피 concat3WordsCurrying("foo")는 함수입니다. 각 호출은 다른 호출을 수락한 다음 최종 결과가 반환될 때까지 새 함수를 반환합니다. 단계별로 진행됩니다. (PS: 여기서는 클로저의 특성을 사용했습니다.)
이제 한 단계 더 나아가서 3개 이상의 매개변수를 전달해야 한다면 원하는 만큼 매개변수를 전달할 수 있습니다. 매개변수가 전달되지 않으면 결과가 출력됩니다.
먼저 일반적인 구현을 해보겠습니다.
var add = function(items){ return items.reduce(function(a,b){ return a+b }); }; console.log(add([1,2,3,4]));
그러나 각 숫자에 10을 곱한 다음 더해야 하는 경우에는 다음을 수행하세요.
var add = function (items,multi) { return items.map(function (item) { return item*multi; }).reduce(function (a, b) { return a + b }); }; console.log(add([1, 2, 3, 4],10));
다행히도 이 모델을 따르고 이제 각 항목에 1을 더한 다음 요약하면 맵의 함수를 교체해야 합니다.
커링 구현을 살펴보겠습니다.
var adder = function () { var _args = []; return function () { if (arguments.length === 0) { return _args.reduce(function (a, b) { return a + b; }); } [].push.apply(_args, [].slice.call(arguments)); return arguments.callee; } }; var sum = adder(); console.log(sum); // Function sum(100,200)(300); // 调用形式灵活,一次调用可输入一个或者多个参数,并且支持链式调用 sum(400); console.log(sum()); // 1000 (加总计算)
위 가산기는 새로운 함수를 반환하는 커리 함수입니다. 새 함수는 새 매개변수를 일괄적으로 받아들이고 마지막까지 계산을 지연할 수 있습니다.
만능 커링 기능
보다 일반적인 커링은 마지막 계산을 함수로 캡슐화한 다음 이 함수를 명확하고 유연한 커링 함수에 매개변수로 전달합니다.
예를 들어 각 항목에 10을 곱하면 처리 기능을 매개변수로 전달할 수 있습니다.
var currying = function (fn) { var _args = []; return function () { if (arguments.length === 0) { return fn.apply(this, _args); } Array.prototype.push.apply(_args, [].slice.call(arguments)); return arguments.callee; } }; var multi=function () { var total = 0; for (var i = 0, c; c = arguments[i++];) { total += c; } return total; }; var sum = currying(multi); sum(100,200)(300); sum(400); console.log(sum()); // 1000 (空白调用时才真正计算)
이렇게 하면 sum = currying(multi) 호출이 매우 명확해지고 사용 효과도 탁월합니다. 예를 들어 여러 값을 누적하려는 경우 여러 값을 매개변수로 사용할 수 있습니다. 1,2,3), 연쇄 호출도 지원 가능, sum(1)(2)(3)
카레의 기본
위 코드는 실제로는 고차 함수입니다. 고차 함수는 하나 이상의 함수를 매개변수로 받아 새로운 함수를 반환하는 함수를 말합니다. 또한 중간 프로세스에서 입력된 매개변수를 저장하기 위해 클로저의 특성에 의존하기도 합니다. 즉,
함수를 매개변수로 전달할 수 있습니다
함수를 함수 반환값으로 사용할 수 있습니다.
폐쇄
카레의 역할
계산이 지연되었습니다. 위의 예는 비교적 설명하기 쉽습니다.
매개변수 재사용. 동일한 함수가 여러 번 호출되고 전달된 매개변수가 대부분 동일한 경우 해당 함수는 커링에 적합한 후보가 될 수 있습니다.
동적으로 함수를 생성합니다. 이는 결과를 부분적으로 계산한 후 후속 비즈니스를 처리하기 위한 새 함수를 동적으로 생성하여 반복 계산을 제거함으로써 수행될 수 있습니다. 또는 호출 함수에 전달될 매개변수의 하위 집합을 함수에 부분적으로 적용하여 새 함수를 동적으로 생성할 수 있습니다. 이 새 함수는 반복적으로 전달되는 매개변수를 저장합니다(매번 전달할 필요는 없음). 미래에). 예를 들어 이벤트 브라우저는 이벤트에 대한 도우미 메서드를 추가합니다.
var addEvent = function(el, type, fn, capture) { if (window.addEventListener) { el.addEventListener(type, function(e) { fn.call(el, e); }, capture); } else if (window.attachEvent) { el.attachEvent("on" + type, function(e) { fn.call(el, e); }); } };
이벤트 처리를 추가할 때마다 if...else를 실행해야 합니다. 사실 브라우저에서는 한 번의 판단 결과를 바탕으로 새로운 함수가 동적으로 생성되기 때문에. 앞으로는 다시 계산할 필요가 없습니다.
var addEvent = (function(){ if (window.addEventListener) { return function(el, sType, fn, capture) { el.addEventListener(sType, function(e) { fn.call(el, e); }, (capture)); }; } else if (window.attachEvent) { return function(el, sType, fn, capture) { el.attachEvent("on" + sType, function(e) { fn.call(el, e); }); }; } })();
이 예에서는 첫 번째 if...else... 판단 후 계산의 일부가 완료되고 나중에 전달된 매개변수를 처리하기 위해 새로운 함수가 동적으로 생성됩니다. 이는 일반적인 커링입니다.
Function.prototype.bind 메소드도 카레 애플리케이션입니다
호출/적용 메소드의 직접 실행과 달리 바인드 메소드는 첫 번째 매개변수를 함수 실행 컨텍스트로 설정하고 나머지 매개변수는 차례로 호출 메소드에 전달됩니다(함수 자체의 본문은 그렇지 않음). 지연 실행으로 간주될 수 있음), 동적 생성은 커링의 특성에 맞는 새로운 함수를 반환합니다.
var foo = {x: 888}; var bar = function () { console.log(this.x); }.bind(foo); // 绑定 bar(); // 888
다음은 바인드 함수의 시뮬레이션입니다. testBind는 새로운 함수를 생성하고 반환하는데, 새 함수에서는 실제로 업무를 수행하는 함수가 실제 매개변수로 전달된 컨텍스트에 바인딩되어 실행이 지연됩니다. .
Function.prototype.testBind = function (scope) { var fn = this; //// this 指向的是调用 testBind 方法的一个函数, return function () { return fn.apply(scope); } }; var testBindBar = bar.testBind(foo); // 绑定 foo,延迟执行 console.log(testBindBar); // Function (可见,bind之后返回的是一个延迟执行的新函数) testBindBar(); // 888
여기서 프로토타입에 대한 이해에 주목해야 합니다.
위 글은 자바스크립트의 함수 커링에 대한 심층 분석입니다. 모두 에디터가 공유한 내용이니 참고가 되셨으면 좋겠습니다. Script Home에 많은 지원 부탁드립니다.