자바스크립트로 커링하기
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.)