본문 바로가기

IT/JavaScript

JavaScript #3 함수-5

14. Currying (커링)
  - 함수와 인수를 결합하여 새로운 함수를 만들 수 있게 한다.
  - 하나의 파라미터를 가진 함수를 여러번 호출하는 것과 같은 방법으로
    여러 개의 파라미터를 가진 함수로 변형하는 것을 말한다.
  - 자바스크립트는 자체적으로 currying 메소드가 없으므로 아래와 같이 구현한다.
  - 개인적으로 어디다 이런 기능을 써야할지는 아직 잘 모르겠다.
[code javascript]
var print = function (strLog) {
    document.write (strLog);
    document.write ('<br>');
};

// 함수 객체에 method 추가
Function.prototype.method = function (name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
    }
};

Function.method ('curry', function () {
     // Array 객체의 slice 메소드를 가져온다.
    var slice = Array.prototype.slice;
     // Array 함수 객체에서 가져온 slice를 실행하는데
     // apply를 사용하여 this객체를 arguments로 바꿔준다.
     // 추후 Array의 concat을 사용하기 위함이다.
     // 왜냐하면 arguments는 length 메소드만을 지원하는 배열이다.
     // 따라서 엄밀히 말하면 배열 객체가 아니다.
     // 아래구문은 arguments를 배열객체로 만들어 args에 할당한다.
    var args = slice.apply (arguments);
     // that 은 curry 메소드를 사용하는 함수 객체를 가리킨다.
    var that = this;
     // curry 함수를 호출한 함수 객체를 변경한다.
     // 변경된 함수 객체를 호출하면 arguments와
     // 처음 curry 메소드 호출시 받은 arguments를
     // 합치게 된다.
    return function () {
        return that.apply (null, args.concat (slice.apply (arguments)));
    };
});

// 단순히 arguments를 모두 더해서 리턴하는 함수객체이다.
var add = function () {
    var iIndex = 0;
    var iCount = arguments.length;
    var iSum = 0;

    for (iIndex = 0; iIndex < iCount; iIndex ++) {
        iSum += arguments[iIndex];
    }
    return iSum;
};

// curry 를 호출해서 add1에 할당된 함수 객체는
// 1 이라는 arguments를 다음에 호출할 때 사용한다.
var add1 = add.curry (1);
// 변경된 add1을 호출한 함수 객체는 1 과 6을
// arguments 로 가지게 되므로 7을 리턴하게 된다.
print (add1 (6)); // 7
[/code]

12. Memoization (메모이제이션)
  - 함수가 이전에 연산한 결과를 저장하고 있는 객체를 사용하는 기법을 말한다.
  - 아래 두 함수를 비교해보면 이 기능을 어디에 쓸지 알 것 같다.
[code javascript]
// 피보나치 수열 함수이다.
// 아래의 연산을 하기 위해서는 453번의 호출이 발생한다.
var fibonacci = function (n) {
    return n < 2 ? n : fibonacci (n - 1) + fibonacci (n - 2);
};

for (var iIndex = 0; iIndex <= 10; i += 1) {
    print ('// ' + i + ': ' + fibonacci (i));
}

// 0: 0
// 1: 1
// 2: 1
// 3: 2
// 4: 3
// 5: 5
// 6: 8
// 7: 13
// 8: 21
// 9: 34
// 10: 55

// 위의 함수를 아래와 같이 변경하면 29번의 호출만 발생한다.
// 그 중 18번은 메모이제이션 결과를 얻기위한 과정이다.
var fibonacci = function () {
    var memo = [0, 1];
    var fib = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = flb (n - 1) + flb (n - 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
} ();
[/code]

    - 아래와 같이 일반화 시킬 수 있다.
[code javascript]
// 결과를 저장할 배열과 메모제이션을 할 함수를 인자로 받는다.
var memoizer = function (memo, fundamental) {
    var shell = function (n) {
        var result = memo [n];
        // 메모에 새로 저장할 데이터이면 fundamental을 호출한다.
        if (typeof result !== 'number') {
            result = fundamental (shell, n);
            memo[n] = result;
        }
        return result;
    };
    return shell;
};

// 피보나치 함수
var fibonacci = memoizer ([0, 1], function (func, n) {
    return func (n -1) + func (n - 2);
});

// 팩토리얼 함수
var factorial = memoizer ([1, 1], function (func, n) {
    return n * func (n - 1);
});
[/code]

공부한 책 : 자바스크립트 핵심가이드 - 더글라스 크락포드