pm100
pm100

Reputation: 50190

javascript curry/partial function invokation for object functions

I want a 'curry' like function - this kind of thing

function invoker (fn) {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments, [1]);
    return function () {
       return fn.apply(null, args);
    };
}

But I want the user to be able to do

invoker(f)

or

invoker(foo.bar)

I cant find the correct magic incantation to do this. All the examples I see require the scope object to be passed in separately; which is error prone and not natural. IE

invokerx(foo.bar, foo)

IS there anyway to do this? I dont mind having 2 different functions

invokeG(f)
invokeO(foo.bar)

EDIT : clarification

'f' is a global scope function
'foo' is an object
'bar is a method on that object

IE I want this curry tool to work with'free' functions as well as with object functions.

Having to go

<curry function>(foo.bar,foo)

seems kinda clunky, I have have to say 'foo' twice

Upvotes: 3

Views: 330

Answers (2)

Brian Nickel
Brian Nickel

Reputation: 27560

The first argument of apply is the this that is available to the function. Since you're passing null, this will get mapped to window.

The following modification will work:

function invoker (fn, target) {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments, [2]);

    if(typeof fn === 'string')
        fn = (target || window)[fn];

    return function () {
       return fn.apply(target || null, args);
    };
}

// Either will work:
invoker(foo.bar, foo);
invoker('bar', foo);

// Any of these will work:
invoker(escape, null);
invoker(escape, window);
invoker('escape', null);
invoker('escape', window);

UPDATE Added a slight change to add support for name passing so you don't have to pass the object name twice.

UPDATE 2 Since we're currying, we need there to always be two arguments.

Upvotes: 4

Eric
Eric

Reputation: 97641

You can't. When you do invoker(foo.bar), invoker has no way of knowing that the argument is a member function of foo. Functions do not store their "owner", and invoker is just passed a reference to a function.

The closest you can get is to use function.bind(), like this:

invoker(foo.bar.bind(foo))

Upvotes: 2

Related Questions