How can I pre-set arguments in JavaScript function call? (Partial Function Application)
Solution 1:
First of all, you need a partial - there is a difference between a partial and a curry - and 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 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 could be used to implement, but is not currying. Here is a quote from a blog post on the difference:
Where partial application takes a function and from it builds a function which takes fewer arguments, currying builds functions which take multiple arguments by composition of functions which each take a single argument.
Hope that helps.
Solution 2:
Using Javascript's apply()
, you can modify the 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 for 2nd argument/parameter.
arguments
is property available inside function which contains all parameters in array like structure.
One 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 kinda suffice, even though little ugly.
Solution 3:
Is curried javascript what you're looking for?
Solution 4:
If you use Dojo you just call dojo.hitch() that does almost exactly what you want. Almost — because it can be used to pack the context as well. But your example is 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 of the Dojo Base, so as soon as you included dojo.js it is there for you.
Another general facility is available in dojox.lang.functional.curry module (documented in Functional fun in JavaScript with Dojo — just look on this page for "curry"). Specifically you may want to look at curry(), and partial().
curry() accumulates arguments (like in your example) but with one difference: as soon as the arity is satisfied it calls the function returning the value. Implementing your example:
df.curry(out)("hello")("world");
df.curry(out)("hello", "world");
Notice that the last line doesn't have "()" at the end — it is called automatically.
partial() allows to replace arguments at random:
df.partial(out, df.arg, "world")("hello");