커링(Curring)
function add(x, y) {
var oldx = x, oldy = y;
if (typeof oldy === 'undefined') { // 부분적인 적용
return function (newy) {
return oldx = newy;
}
}
// 전체 인자를 적용
return x + y;
}
//테스트
typeof add(5); // "function"
add(3)(4); // 7
// 새로운 함수를 만들어 저장
var add200 = add(200);
add200(10); // 2010
function add(x, y) {
if (typeof y === "undefined") {
return function (y) {
return x + y;
}
}
// 전체 인자를 적용
return x + y;
}
여기에는 oldx, oldy가 없는데 원래 x는 암묵적으로 클로저에 저장되어 있고, y는 재사용을 하고 있다.
조금더 범용적인 방식으로 처리할 수 있을까?
어떤 함수라도 부분적인 매개변수를 받는 새로운 함수로 변형할 수 있을까?
function flexible_curry(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function () {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
되게 복잡해 보이는 이유는 단시 arguments가 배열이 아니기 때문이다. slice를 쓰고 싶은데 arguments는 배열처럼 보일 뿐 배열이 아니기 때문에 var slice = Array.prototype.slice로 slice안에 메소드를 넣었다. 그리고는 slice.call(arguments, 1); argument를 배열의 메소드로 배열처럼 사용하는 것이다. 이해가 안된다면
[1, 2, 3, 4, 5].slice(1); // [2, 3, 4, 5] Array.prototpye.slice.call([1, 2, 3, 4, 5], 1);이제 테스트를 해보자
function add(x, y) {
return x + y;
}
function flexible_curry(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function () {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
var newadd = flexible_curry(add, 5);
newadd(5); // 10
add(fn)는 클로저로서 값이 휘발성으로 사라지지 않는다. (객체화도 되지 않았는데 어떻게?) 그것이 클로저다. 나중에 좀 더 공부해보도록 하자. 어쨋든 argument에서 첫번째 것만을 잘라내서(slice) sotred_args에 넣기 위해 Array.prototype.slice.call(arguments, 1)을 사용하였다.그리고 반쪽자리 add(fn)를 반환한다. 그것을 newadd에 넣었고 newadd(5)를 실행하면 더하기를 수행 할 것이다. 여기서 concat은 배열끼리의 접합을 수행한 후, args에 넣는다. 그 후 fn.apply(null, args); 를 실행한다. (apply는 call과 비슷하게 동작하지만 배열을 받는 다는 것을 기억하라. 이 예제에서 apply는 아주 잘 맞는다.)
function multifly(a, b, c, d, e) { return a * b * c * d * e; }
function flexible_curry(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function () {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
flexible_curry(multifly, 1, 2, 3)(5, 5);
var a = flexible_curry(multifly, 1.534);
a(10, 10, 10, 10);
var b = flexible_curry(a, 2, 3);
b(6, 7);
커링은 엄청난 자유를 준다.
댓글 없음:
댓글 쓰기