함수 커링: 자바스크립트 질문

작은 소개



커링은 함수가 모든 매개변수를 한 번에 받지 못할 때 발생합니다. 대신 첫 번째 매개변수를 사용하고 다른 함수를 반환합니다. 반환된 함수는 다른 함수를 반환해야 하는 두 번째 매개 변수로 호출되어야 합니다. 이것은 모든 인수가 제공될 때까지 계속됩니다. 그러면 체인 끝에 있는 함수가 원하는 값을 반환하는 함수가 됩니다.

// This is a normal function
sum(1,2,3)

// while this is a curried function
sum(1)(2)(3)


It is important to note that currying only alters the construct of a function and not it's functionality.



질문-1: 합계(1)(2)



이것은 매우 간단합니다. 문법이 처음 보는 분들에게는 조금 생소할 수 있습니다. 기본적으로 우리는 함수를 계속 반환하고 하나의 인수를 전달합니다. 이것은 모든 인수 전달을 마친 후에도 계속됩니다. 마지막 단계에서 클로저의 힘으로 인해 이전에 전달된 모든 인수에 액세스할 수 있습니다. 이 단계에서 논리를 실행합니다.

function sum(a){
 return function(b){
   return a + b;
 }
}

// dry-run
// add(1)(2)
// step - 1: add(1) executes and returns a function

// (function(b){
//   return 1 + b;
// })(2)

// step - 2: returned function executes with 2 passed as parameter.

// (function(2){
//   return 1 + 2 //> it gets value of 1 from closure!
// })

// outputs 3

console.log(sum(1)(2)) //logs 6



질문-2: sum(1)(2)(3)(4)...(n)()



이 질문은 첫 번째 질문의 직접적인 확장입니다. 인수의 수는 무한할 수 있습니다! 이 문제는 일반적으로 무한 커링으로 알려져 있으며 인기 있는 인터뷰 질문입니다.

Always solve for a smaller subproblem.



// with 2 arguments
function sum2(a){
 return function(b){
   return a + b;
 }
}

// with 3 arguments
function sum3(a){
 return function(b){
   return function(c){
     return a + b + c;
   }
 }
}

// notice the pattern here ? At every level,
// If there is another argument left, we return a new function
// else we execute the logic. Recursive thinking is required for // these pattern of problems.

//with n-arguments
function sum(a) {
  return function(b){
    if(b){
      return sum(a+b);
    }
    return a;
  }
}

// dry-run
// example -> sumN(1)(2)(3)(4)

// step-1 
//   sumN(1) executes

// step-2 
//   (function(b){
//     if(b){
//       return sumN(1+b);
//     }
//     return a;
//   })(2)(3)(4)

// step-3
//    (function(2){
//     if(2){
//       return sumN(1+2); // again call to sum
//     }
//     //> won't execute
//     return a;
//   })(3)(4)


// // Notice the recursive pattern ?
// step-4 
//    (function sumN(3) {
//     return function(b){
//       if(b){
//         return sumN(3+b);
//       }
//       return a;
//     }
// })(3)(4)

// step-5
//   (function sumN(3) {
//   return function(3){
//     if(b){
//       return sumN(3+3);
//     }
//     return a;
//   }
// })(4)

// step-6
//  (function sumN(6) {
//   return function(b){
//     if(b){
//       return sumN(6+b);
//     }
//     return a;
//   }
// })(4)

// step-7
//   (function(4){
//     if(4){
//       return sumN(6+4);
//     }
//     return a;
//   })

// step-8
//   sumN(10)

// step-9
//   (function(undefined){
//     if(undefined){
//       //> won't execute
//       return sum(a+b);
//     }
//     return 10;
//   })()

// step-10
//   logs 10


아무 IDE에서든 코드를 작성하고 직접 테스트해 보는 것이 좋습니다.

질문-3 sum(1,2,...,n)(3,4,...,n)...(n)()



우리는 여기서 게임을 강화하고 있습니다. 이 패턴에서 단일 호출의 인수 수도 무한할 수 있습니다! 우리는 이것을 해결하기 위해 지난 문제에서 얻은 지식을 사용할 것입니다.

힌트: 이 문제는 바로 마지막 문제로 줄일 수 있습니다.

// we just reduce the arguments into a single argument for
// a single call! Now it's just like the previous problem!
function sum(...args) {
  let a = args.reduce((a, b) => a + b, 0)
  return function(...args){
    let b = args.reduce((a, b) => a + b, 0)
    if(b){
      return sum(a+b)
    }
    return a
  }
}


질문 4 currify 함수 구현



Currify는 다른 함수를 인수로 받아 같은 함수의 currified 버전을 반환하는 함수가 될 것입니다! 어떤 식으로든 전달된 함수의 기능을 수정하지 않습니다. 기능만 변환합니다.

자, 이것은 약간 까다 롭습니다.

문제를 해결하는 일반적인 아이디어는 다음과 같습니다.
  • Currify는 함수를 인수로 사용합니다.
  • Currify가 다른 함수를 반환합니다.
  • 해당 함수의 사용 사례는 전달할 인수가 더 이상 없을 때까지 전달되는 모든 인수를 저장하는 것입니다.
  • 모든 인수가 소진되면 누적된 모든 인수를 사용하여 전달된 함수를 호출하기만 하면 작업이 완료됩니다.

  • 아래는 위의 아이디어를 코드로 표현한 것입니다.

    function currify(fn) {
      return function saveCurryArgs() {
        const args = Array.prototype.slice.call(arguments); // a
        if (args.length >= fn.length) // b
          return fn.apply(null,args); //c
        else 
          return saveCurryArgs.bind(null, ...args); //d
      }
    }
    
    const multiply = function(a,b,c){
      return a + b + c 
    }
    
    const curryMultiply  = currify(multiply);
    
    // logs 6
    console.log(curryMultiply(1)(2)(3));
    


    그것이 무엇을 하고 있고 어떻게 하는지 정확히 이해합시다.
    코드의 주요 논리 포인트를 알파벳으로 주석 처리했습니다.

    a) array-like object arguments 에서 인수 목록을 구성합니다.

    b) args.length는 지금까지 받은 인수를 나타냅니다. fn.length는 처리할 총 인수 수를 나타냅니다.

    c) 이 논리는 인수를 모두 사용한 후에 실행됩니다. 우리는 단순히 fn에 적용 방법을 사용합니다.

    d) 그렇지 않으면 saveCurryArgs 함수에 대해 bind를 호출하여 모든 이전 인수와 함께 현재 인수를 저장합니다.

    이로써 currify 로직이 완성되었습니다!

    결론



    여기까지 왔다면 축하합니다! Currying은 인터뷰 관점과 실제 사용 사례에서 매우 중요한 주제입니다. codepen 또는 로컬 IDE를 통해 예제를 코딩하는 것이 좋습니다. 당신이 기사를 즐겼기를 바랍니다! 읽어주셔서 감사합니다!

    좋은 웹페이지 즐겨찾기