자바스크립트로 커링하기
Currying은 함수로 작업할 때 고급 기술이며 여러 프로그래밍 언어에서 사용됩니다.
여러 인수를 취하는 함수를 일련의 중첩 함수로 분해하면 카레가 생깁니다. 각 중첩 함수는 함수에 대한 다음 인수를 가질 것으로 예상합니다.
카레 함수는 각 호출에 대해 모든 인수가 수신될 때까지 매번 새 함수를 반환합니다. 이 인수는 클로저를 통한 커링의 수명 동안 지속될 수 있으며 모두 최종 기능을 실행하는 데 사용됩니다.
매우 기본적인 예는 다음과 같습니다.
function combineWords(word) {
return function(anotherWord) {
return function(andAnotherWord) {
return `${word} ${anotherWord} ${andAnotherWord}`
}
}
}
이를 사용하려면 마지막 함수에 도달할 때까지 함수를 여러 번 호출할 수 있습니다.
const result = combineWords('hello,')('good')('morning')
console.log(result)
// result: 'hello, good morning'
그래서 무슨 일이 일어나고 있는지는
combineWords 커리 함수이고 (분명히) 단어가 주어질 때까지 기다렸다가 시리즈의 다음 함수를 실행합니다. 'wow!'를 combineWords 변수에 바인딩하고 재사용하여 'wow!'로 시작하는 다른 인사말을 만들 수 있습니다.let greet = combineWords('wow!')
greet = greet('nice')
console.log(greet('jacket'))
console.log(greet('shoes'))
console.log(greet('eyes'))
console.log(greet('socks'))
console.log(greet('hat'))
console.log(greet('glasses'))
console.log(greet('finger nails'))
console.log(greet('PS3'))
console.log(greet('pet'))
/*
result:
"wow! nice jacket"
"wow! nice shoes"
"wow! nice eyes"
"wow! nice socks"
"wow! nice hat"
"wow! nice glasses"
"wow! nice finger nails"
"wow! nice PS3"
"wow! nice pet"
*/
개념이 이해하기 조금 어렵다면 다음과 같이 읽어보십시오.
The mother is expecting all 4 eggs (arguments) before cooking and her 4 children will each carry one to her, one at a time.
function Egg() {...}
// the curry func
function prepareCooking(cook) {
return function(egg1) {
return function(egg2) {
return function(egg3) {
return function(egg4) {
return cook(egg1, egg2, egg3, egg4)
}
}
}
}
}
const cook = function(...eggs) {
api.turnOnStove()
api.putEggsOnTop(...eggs)
api.pourSalt()
api.serve()
console.log('served children')
return 'served'
}
const start = prepareCooking(cook)
let collect = start(new Egg())
collect = collect(new Egg())
collect = collect(new Egg())
collect = collect(new Egg()) // this steps into the last function witih argument "egg4" which will invoke the callback passed to "prepareCooking"
// result: console.log --> "served children"
// collect === 'served'
cook 콜백이 호출되려면 4개의 모든 에그가 차례로 전달되어야 하며, 각각은 호출을 기다리는 다음 함수를 미리 채웁니다.세 번째 달걀에서 멈출 경우:
let collect = start(new Egg())
collect = collect(new Egg())
collect = collect(new Egg())
그런 다음 예상되는 마지막 함수
egg4에 아직 도달하지 않았으므로 collect 값은 해당 함수입니다.function prepareCooking(cook) {
return function(egg1) {
return function(egg2) {
return function(egg3) {
// HERE
return function(egg4) {
return cook(egg1, egg2, egg3, egg4)
}
}
}
}
}
카레를 완성하려면 마지막 달걀을 모으십시오.
let collect = start(new Egg())
collect = collect(new Egg())
collect = collect(new Egg())
collect = collect(new Egg())
// collect === 'served'
이제 각 중첩 함수가 카레 함수 내 외부 범위에 대한 모든 액세스 권한을 갖는다는 것을 아는 것이 중요합니다. 이를 알면 각 중첩 함수 사이에 사용자 정의 논리를 제공하여 특정 상황에 맞출 수 있습니다. 그러나 카레는 카레로 남겨두는 것이 가장 좋습니다.
좀 더 발전된 카레 기능은 다음과 같습니다. (
ES5 버전과 ES6 버전을 제공하겠습니다. ES5 구문을 보여주는 오래된 자습서가 많이 있기 때문입니다. 최신 JavaScript 개발자)ES5
function curry(fn) {
return function curried() {
const args = Array.prototype.slice.call(arguments)
const done = args.length >= fn.length
if (done) {
return fn.apply(this, args)
} else {
return function() {
const args2 = Array.prototype.slice.call(arguments)
return curried.apply(this, args.concat(args2))
}
}
}
}
...와 같다:
ES6
const curry = (fn) => {
return function curried(...args) {
const done = args.length >= fn.length
if (done) {
return fn.apply(this, args)
} else {
return (...args2) => curried.apply(this, [...args, ...args2])
}
}
}
이 예를 더 자세히 설명하겠습니다.
curry(fn)를 호출하면 호출 시 다음 인수를 기다리는 내부curried 함수가 반환됩니다. 이제 이 내부 함수를 호출하면 두 가지 조건이 평가됩니다.fn의 모든 인수를 충족하기에 충분한 인수를 전달했습니까? fn 필요한 인수가 아직 누락되어 있습니까? 숫자 1인 경우 필요한 모든 인수
fn를 선언했으며 카레는 fn 호출을 반환하고 수신된 모든 인수를 전달하여 종료됩니다(기본적으로 현재 일반적으로 fn 호출).그러나 숫자 2인 경우 카레는 계속 진행되어야 하며
curried 의 인수를 충족할 때까지 더 많은 인수를 계속 수신할 수 있도록 어떻게든 내부 fn 함수로 돌아가야 합니다. 코드return (...args2) => curried.apply(this, [...args, ...args2])는 지금까지 노출된 모든 인수를 누적하고 이 경우 카레를 계속하는 데 사용합니다.한 가지 중요한 규칙이 있습니다.
The function that is to be invoked before waiting for all the arguments to be collected must have a fixed number of arguments. This means that the function cannot have parameters spreaded (ex:
fn(...args))
전:
const curry = (fn) => {
return function curried(...args) {
const done = args.length >= fn.length
if (done) {
return fn.apply(this, args)
} else {
return (...args2) => curried.apply(this, [...args, ...args2])
}
}
}
// This is invalid because it uses ...args. The curry does not understand where to stop
function func(...args) {
//
}
const currying = curry(func)
결론
카레를 만드는 것은 다른 고급 기술을 조합해야 하기 때문에 카레를 만드는 것이 흥미로운 기술이라고 생각합니다. 관련된 클로저, 고차 함수 및 재귀가 있습니다.
그리고 이상으로 이번 포스팅을 마칩니다. 소중한 것을 발견하셨기를 바라며 앞으로도 많은 관심 부탁드립니다!
medium에서 나를 찾아라
Reference
이 문제에 관하여(자바스크립트로 커링하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jsmanifest/currying-inside-javascript-2gbl텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)