[ACCEPTED]-How can I pre-set arguments in JavaScript function call? (Partial Function Application)-functional-programming

Accepted answer
Score: 97

First of all, you need a partial - there is a difference between a partial and a curry - and 9 here is all you need, without a framework:

function partial(func /*, 0..n args */) {
  var args = Array.prototype.slice.call(arguments, 1);
  return function() {
    var allArguments = args.concat(Array.prototype.slice.call(arguments));
    return func.apply(this, allArguments);
  };
}

Now, using your example, you 8 can do exactly what you are after:

partial(out, "hello")("world");
partial(out, "hello", "world")();

// and here is my own extended example
var sayHelloTo = partial(out, "Hello");
sayHelloTo("World");
sayHelloTo("Alex");

The partial() function 7 could be used to implement, but is not currying. Here 6 is a quote from a blog post on the difference:

Where partial application 5 takes a function and from it builds a function 4 which takes fewer arguments, currying builds 3 functions which take multiple arguments 2 by composition of functions which each take 1 a single argument.

Hope that helps.

Score: 3

Is curried javascript what you're looking for?

0

Score: 3

Using Javascript's apply(), you can modify the 6 function prototype

Function.prototype.pass = function() {
    var args = arguments,
        func = this;
    return function() {
        func.apply(this, args);
    }
};

You can then call it as out.pass('hello','world')

apply takes an array 5 for 2nd argument/parameter.

arguments is property 4 available inside function which contains 3 all parameters in array like structure.

One 2 other common way to do this is to use bind

loadedFunc = func.bind(this, v1, v2, v3);

then

loadedFunc() === this.func(v1,v2,v3);

this 1 kinda suffice, even though little ugly.

Score: 2

If you use Dojo you just call dojo.hitch() that 17 does almost exactly what you want. Almost 16 — because it can be used to pack 15 the context as well. But your example is 14 first:

dojo.hitch(out, "hello")("world");
dojo.hitch(out, "hello", "world")();

As well as:

var A = {
  sep: ", ",
  out: function(a, b){ console.log(a + this.sep + b); }
};

// using functions in context    
dojo.hitch(A, A.out, "hello")("world");
dojo.hitch(A, A.out, "hello", "world")();

// using names in context
dojo.hitch(A, "out", "hello")("world");
dojo.hitch(A, "out", "hello", "world")();

dojo.hitch() is the part 13 of the Dojo Base, so as soon as you included 12 dojo.js it is there for you.

Another general 11 facility is available in dojox.lang.functional.curry 10 module (documented in Functional fun in JavaScript with Dojo — just 9 look on this page for "curry"). Specifically 8 you may want to look at curry(), and partial().

curry() accumulates 7 arguments (like in your example) but with 6 one difference: as soon as the arity is 5 satisfied it calls the function returning 4 the value. Implementing your example:

df.curry(out)("hello")("world");
df.curry(out)("hello", "world");

Notice 3 that the last line doesn't have "()" at 2 the end — it is called automatically.

partial() allows 1 to replace arguments at random:

df.partial(out, df.arg, "world")("hello");
Score: 1

You could use Function.prototype.bind() for this. It's an ES5 addition.

In 8 addition to the common usecase of setting 7 a function's context (this value), it can also 6 set partial arguments.

function out(a, b) {
  document.write(a + " " + b);
}

function setter(func) {
  return func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1)));
}

setter(out, "hello")("world");
setter(out, "hello", "world")();

My setter function is actually 5 very simple. The longest part is just getting 4 the list of arguments. I'll break up the 3 code like this:

func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1)))
func.bind.apply(                                                        )  // need to use apply to pass multiple arguments as an array to bind()
                func,                                                      // apply needs a context to be run in
                      [window].concat(                                 )   // pass an array of arguments to bind(), starting with window, to be the global context
                                      [].slice.call(arguments).slice(1)    // convert the arguments list to an array, and chop off the initial value

It's supported in these browsers: Chrome 2 7+, Firefox 4+, IE9+. MDN (linked at the 1 beginning) has a polyfill though.

Score: 1

Easy way to achieve presetting of parameters 4 without calling the function straight away 3 (when e.g. awaiting user confirmation), is 2 to "dress" the function in another anonymous 1 function.

Instead of: exportFile(docType)

Do: function(){ return exportFile(docType) }

Score: 0

** EDIT: See Jason Bunting's response. This 13 answer actually shows a sub-par way of chaining 12 numerous out calls, not a single out-call 11 with presets for some of the arguments. If 10 this answer actually helps with a similar 9 problem, you should be sure to make use 8 of apply and call as Jason recommends, instead 7 of the obscure way to use eval that I thought 6 up. **

Well... your out will actually write 5 "undefined" a lot in this... but this should 4 be close to what you want:

function out(a, b) {
    document.write(a + " " + b);
}

function getArgString( args, start ) {
    var argStr = "";
    for( var i = start; i < args.length; i++ ) {
        if( argStr != "" ) {
            argStr = argStr + ", ";
        }
        argStr = argStr + "arguments[" + i + "]"
    }
    return argStr;
}

function setter(func) {
    var argStr = getArgString( arguments, 1 );
    eval( "func( " + argStr + ");" );
    var newSettter = function() {
        var argStr = getArgString( arguments, 0 );
        if( argStr == "" ) {
            argStr = "func";
        } else {
            argStr = "func, " + argStr;
        }
        return eval( "setter( " + argStr + ");" );
    }
    return newSettter;
}

setter(out, "hello")("world");
setter(out, "hello", "world")();

I'd probably move 3 the code in getArgString into the setter 2 function itself though... a little bit safer 1 since I used 'eval's.

Score: 0

Using closures is another option. Use functions 1 that return other functions!

More Related questions