Skip to content

Instantly share code, notes, and snippets.

@nephilim
Last active December 13, 2015 21:19
Show Gist options
  • Save nephilim/4976804 to your computer and use it in GitHub Desktop.
Save nephilim/4976804 to your computer and use it in GitHub Desktop.
Created to demonstrate one of possible problems with a sample code in chapter four of the book Javascript Patterns. For more information, refer to an example on page 100 of the book
function curry(fn) {
var slice = Array.prototype.slice;
var args = slice.call(arguments);
// curry.call(obj)의 형태로 호출했을 경우
var self = this;
if (typeof(args[0]) != "function") {
// 예외 처리
throw { name: "ArgumentException",
message: "First argument should be a function" };
}
called_args = args.slice(1);
return function() {
// 명시적으로 self를 지정하지 않고
// this를 사용하면 반환된 함수를 사용하는 scope을 따라간다.
args = slice.call(called_args).concat(arguments);
// 책에 있는 예제와 달리 captured variable인 self를 전달함
return fn.apply(self, args);
};
}
var obj = {
base: 10,
add_to_base: function() {
// 인자 개수에 상관없이 동작하느라 좀 길지만,
// 결국 base에 인자를 모두 더하는 함수
var args = Array.prototype.slice.call( arguments, 0);
sum = this.base;
for(var i =0; i < args.length; i++) {
sum += args[i];
}
return sum;
}};
/*
var add_to_hundred = curry.call(obj, obj.add_to_base, 90)
add_to_hundred(100)
> 200
// 책의 예제는 다음과 같아서 실패함
var add_to_hundred = curry.call(null, obj.add_to_base, 90)
add_to_hundred(100)
> NaN
*/
@outsideris
Copy link

Secrets of the JavaScript Ninja에 나온 curry 예제입니다.(비교하면서 얘기해봐도 잼날듯해요.)

Function.prototype.curry = function() {
  var fn = this,
      args = Array.prototype.slice.call(arguments);
      return function() {
        return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
      }
}

@nephilim
Copy link
Author

@outsideris "네피림 비켜~ 내가 진정한 자바스크립트 닌자야"라고 말하고 있군.

@nephilim
Copy link
Author

아닌자님과는 이야기한 내용이지만, 레식옹의 방법 또한 다음과 같은 결과가 나옵니다. 이 글타레를 (혹시나) 보시는 분이 있을 까봐 코드를 추가합니다.

    var person = { age: 30, 
            yearsAfter: function( a,b,c) { return this.age + a + b + c; } 
    }

    var yearsAfterTenYearsLater = person.yearsAfter.curry(10);
    yearsAfterTenYearsLater(20,30);
    // NaN

@nephilim
Copy link
Author

@outsideris 참고로 "아닌자"라는 발음은 보난자와 상당히 비슷하네요.

@outsideris
Copy link

var a = function() {return this.age;}
a.curry().apply({age:5})
a.curry().apply({age:7})

@nephilim
Copy link
Author

아닌자 님의 코드는 다음과 같이 obj의 문맥을 적용할 수 있습니다.

    obj.add_to_base.curry(20, 30).call(obj, 40)
    // 100

    obj.base60  = obj.add_to_base.curry(20, 30)
    obj.base60(40)
    // 100

개인적으로는 커리된 함수를 obj의 멤버로 지정하는 두 번째 방법이 좋아보입니다. 하지만 해당 문맥에 넣지 않으면 안되고, call/apply를 적용하는 건 애초에 불가능합니다. 이건 var fn = this 때문이기도...

this를 사용하는 레식옹의 코드도 나쁘지 않기는 한데... 어쨌던 제 방법에 레식옹의 function prototype을 적용하는 것은 생각해보지 못했네요, 책의 예제를 벗어나서 생각해본 건 아닌데... (부들부들)

@nephilim
Copy link
Author

@outsideris 그래도 지구는 돈다 궁시렁 궁시렁 @McTenshi 도와죠

@goonoo
Copy link

goonoo commented Feb 20, 2013

초대 감사합니다. ㅋㅋ

"아닌자"라니 "Non-person" 같군요.

레식옹의 방법은 function의 prototype으로 하지 않았을 때 첫번째 인자가 function인지 검사하는 로직을 구조적으로 해결했다는 것이 참 아름답군요.

그나저나 두 코드가 비슷한걸 보니 네피림님에게서도 닌자의 향기가...

@outsideris
Copy link

마지막줄에.. +1 입니다.

@outsideris
Copy link

@nephilim 닌자님의 인술이 더 강력했습니다...

@nephilim
Copy link
Author

@outsideris 전 닌자가 아니에욧! 어쨌건 제 주장을 이해해 주시니 감사. (하지만 레식옹 코드 보자마자 이야기 했는데... 역시 보고 있지 않았;;; )

@McTenshi '아-닌자'로도 '아닌-자'로도 읽히는 군요. 두 개의 별명을 한 큐에!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment