본문 바로가기

FRONT-END/JAVASCRIPT

자바스크립트 디자인 패턴 #10. curring 패턴

반응형

curring 패턴

커링패턴

함수를 설계할 때 인자 전체를 넘겨서 호출할 수 도 있지만, 일부 인자는 먼저 입력해두고 나머지만 입력받을 수 있도록 새로운 함수를 만드는 패턴을 의미한다.

특히 자바스크립트에서 클로저가 있어서 먼저 일부 입력된 값을 유지하고, 가지고 있는 것을 아주 쉽게 구현할 수 있기 때문에 유용하게 사용할 수 있는 패턴이다.

(function(){

  function sum(x, y){

    return x + y;

  }


  var makeAdder = function(x){

    return function(y){

      return sum(x,y);

    };

  };


  var adderFour = makeAdder(4);

  console.log(adderFour(1));  //5

  console.log(adderFour(5));  //9


}());

더하기 함수는 x와 y 두개의 인자를 받는다.

그런데 커링 패턴을 적용하면 사전에 x인자는 입력해두고, 별도의 함수를 생성하여 y만 입력하면 자동으로 x를 더하게 할 수 있다.

makeAdder()함수로 인자를 하나 받은뒤, 나머지 인자를 하나 받는 함수를 반환한다.

여기서 반환된 함수가 호출되면 클로저로 저장되어 있던 x 와 새로 입력되어 들어온 y를  sum() 함수의 인자로 넘긴다.

그 결과 x의 값을 4을 먼저 고정하고 이후 y만 입력하더라도 sum(x, y)의 결과가 나온다.


(function(){

  Function.prototype.curry = function(){

    if(arguments.length < 1){

      return this;

    }

    var _this = this;

        args = Array.prototype.slice.apply(arguments);

    return function(){

      return _this.apply(this, args.concat(Array.prototype.slice.apply(arguments)));

    }

  }

  function sum(x, y){

    return x + y;

  }


  var adderFourCurry = sum.curry(4);

  console.log(adderFourCurry(5));  //9

  console.log(adderFourCurry(10)); //14


  function sum4(x, y, z, w){

    return x + y + z + w;

  }


  var adderCurry = sum4.curry(5, 1);

  console.log(adderCurry(2, 3));  //11

}());

sum()함수의 인자를 여러 개를 동적으로 받으면서 Function.prototype에 추가해서 기존 함수들이 쉽게 커링 패턴을 적용할 수 있다.

sum4() 함수는 4개의 인자를 받고 있으며, curry()함수에는 5,1 두개의 인자를 먼저 적용해놓았다.

여기서 추가로 2와 3을 인자로 넘겨 주면 총합 11이 반환되는 것을 확인할 수 있다.

이처럼 자바스크립트는 arguments 객체와 apply() 함수로 가변 인자들을 유동적으로 변경하고 클로저를 통해 먼저 넘어온 데이터 값에 대한 보관까지 쉽게 할 수 있다.


(function(){

  Function.prototype.curry = function(){

    if(arguments.length<1){

      return this;

    }

    var _this = this,

        args = Array.prototype.slice.apply(arguments);

    return function(){

      console.log(arguments);

      return _this.apply(this, args.concat(Array.prototype.slice.apply(arguments)));

    }

  }


  function unitConvert(fromUnit, toUnit, factor, input){

    return `${input} ${fromUnit} === ${(input*factor).toFixed(2)} ${toUnit}`;

  }


  var cm2inch = unitConvert.curry('cm','inch',0.393701),

      metersquqre2pyoung = unitConvert.curry('m^2','pyoung',0.3025),

      kg2lb = unitConvert.curry('kg','lb', 2.204623),

      kmph2mph = unitConvert.curry('km/h','mph', 0.621371);


  console.log(cm2inch);

  console.log(cm2inch(10));

  console.log(metersquqre2pyoung(30));

  console.log(kg2lb(50));

  console.log(kmph2mph(100));




}());


unitConvert() 함수에서 변환할 단위들을 받고 변환될 계수를 먼저 인자로 받은 다음, 나중에 input만 받도록 하고 있다.

특수 목적의 함수가 아니라 일반적인 웹페이지에서 사용할 수 있는 함수라면 앞서 잠깐 사용했던 ajax()함수를 커링 패턴으로 조금 변경할 수 있다.

(function(){

  Function.prototype.curry = function(){

    if(arguments.length<1){

      return this;

    }

    var _this = this,

        args = Array.prototype.slice.apply(arguments);

    return function(){

      console.log(arguments);

      return _this.apply(this, args.concat(Array.prototype.slice.apply(arguments)));

    }

  }


  function ajax(method, url, data, callback){

    var xhr = new XMLHttpRequest();

    xhr.open(method, url);

    xhr.onload = function(){

      if(xhr.status === 200){

        callback.call(this, xhr.responseText);

      }

    }

    xhr.send(data);

  }


  var ajaxGet = ajax.curry("GET"),

      ajaxPost = ajax.curry("POST"),

      ajaxPut = ajax.curry("PUT"),

      ajaxDelete = ajax.curry("DELETE");



      ajaxGet("/data", null, function(responseText){

        console.log(responseText);

      });


}());

REST API에서 자주 사용하는 XMLHttpRequest의 4가지 메소드에 대해서 별도의 ajax()함수로 정의하여 사용할 수 있다.

이러한 방식은 이미 jQuery 라이브러리에서도 사용하는 방식으로 순수 자바스크립트만으로 쉽게 구현할 수 있다.


이처럼 커링 패턴은 자바스크립트의 언어적 특징 때문에 아주쉽게 구현할 수 있으며, 인자가 많은 공통 라이브러리를 사용할 때 유용하게 활용할 수 있다는 장점이 있다.

하지만 클로저도 그렇지만 프로그램이 돌아가는 순서를 쫓아가기에는 조금 힘들수 도 있다는 단점도 있으니 개발 효율성과 소스 관리에 대한 균형을 잘 맞춰야 한다.


출처-속깊은 자바스크립트 양성익 지음

반응형