How can I pre-set arguments in a JavaScript function call? (Partial Function Application)

I am trying to write a JavaScript function that returns its first argument (function) with all its other arguments as the given parameters for this function.

So:

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

 function setter (...) {...}

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

Print hello world twice. for some setter implementation

I had a problem manipulating an array of arguments on my first try, but it seems like this would be the best way to do this.

+53
javascript functional-programming
Nov 26 '08 at 15:33
source share
7 answers

First of all, you need partial - there is a difference between partial and curry - and that's all you need without a frame:

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 what you need:

 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 can be used to implement, but is not executed. Here is a quote from a blog post about the difference :

If a partial application takes a function and builds a function from it that takes fewer arguments, currying builds functions that take several arguments according to the composition of the functions, each of which takes one argument.

Hope this helps.

+96
Nov 26 '08 at 17:39
source share

Is your javascript what you are looking for?

+3
Nov 26 '08 at 15:38
source share

If you use Dojo, you simply call dojo.hitch (), which does almost what you want. Nearly; because it can also be used to package context. 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 part of the Dojo base, so once you have included dojo.js, it is there for you.

Another publicly available tool is available in the dojox.lang.functional.curry module (registered in Functional Fun in JavaScript with Dojo Just look at this page for "curry"). In particular, you can look at curry () and partial ().

curry () accumulates arguments (as in your example), but with one difference: as soon as legitimacy is executed, it calls a function that returns a value. Implementation of your example:

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

Note that the last line does not have a "()" at the end - it is called automatically.

partial () allows you to arbitrarily replace arguments:

 df.partial(out, df.arg, "world")("hello"); 
+2
Nov 26 '08 at 16:21
source share

Using Javascript apply() , you can change the function prototype

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

Then you can call it out.pass('hello','world')

apply takes an array for the second argument / parameter.

arguments is a property available inside a function that contains all the parameters in an array structure, like a structure.

Another common way to do this is to use bind

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

then

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

this kind is enough, albeit a little ugly.

+1
Dec 15 '17 at 6:29
source share

** EDIT: see Jason Bunning's answer. This answer actually shows a sub-pairing way of chaining multiple calls, rather than a single outgoing call with presets for some arguments. If this answer actually helps with a similar problem, you should definitely use the application and call, as Jason recommends, instead of the obscure way to use the eval that I came up with. **

Ok ... your output will really write "undefined" a lot in this ... but this should 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 would probably move the code in getArgString to the setter function, though ... a bit safer since I used 'eval's.

0
Nov 26 '08 at 17:00
source share

You can use Function.prototype.bind() . This is an ES5 add-on.

In addition to the general utility for setting the context of the function ( this value), it can also 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 very simple. The longest part is just a list of arguments. I will break the code as follows:

 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 supports these browsers : Chrome 7+, Firefox 4+, IE9 +. MDN (linked at the beginning) has a polyfill, though.

0
Jun 18 '15 at 21:32
source share
 function myLog(arg1,arg2,arg3){ return function(){ //you can use the arguments from the parent scope console.log(arg1+" "+arg2+" "+arg3); }; } var passMeAnywhere = myLog(1,2,3); //execute the function, args will be in the immediate lexical scope. passMeAnywhere(); //One of the previous posts showed a way for context binding //Context binding allows any context //New is not required with binding 
0
Dec 12 '15 at 7:15
source share



All Articles