In JavaScript I can bind arguments to a function like so..
function foo(arg1, arg2) { console.log(arguments); }
foo = foo.bind(this, 'bar');
When called, we get this output...
foo('baz');
> { '0': 'bar', '1': 'baz' }
Is it possible to skip arguments in the .bind() function to achieve the following output?
function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = foo.bind(this, 'bar', null, 'qux');
foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '2': 'lel', '3': 'qux' }
In JavaScript I can bind arguments to a function like so..
function foo(arg1, arg2) { console.log(arguments); }
foo = foo.bind(this, 'bar');
When called, we get this output...
foo('baz');
> { '0': 'bar', '1': 'baz' }
Is it possible to skip arguments in the .bind() function to achieve the following output?
function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = foo.bind(this, 'bar', null, 'qux');
foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '2': 'lel', '3': 'qux' }
Share
Improve this question
asked Sep 3, 2015 at 2:59
ZeunO8ZeunO8
4507 silver badges26 bronze badges
1
- I don't think so.. if you don't need that argument why pass it – Arun P Johny Commented Sep 3, 2015 at 3:01
4 Answers
Reset to default 5Take a look at Underscore's _.partial
:
Partially apply a function by filling in any number of its arguments, without changing its dynamic this value. You may pass _ in your list of arguments to specify an argument that should not be pre-filled, but left open to supply at call-time.
In your case:
function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = _.partial(foo, 'bar', _, 'qux');
foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '3': 'qux', '4': 'lel'}
Yes, I know this is not exactly what you said you wanted. You seem to want both arguments to be squeezed in where the _
is. There is no good way around that other than explicitly specifying that two arguments will be filled in at the time of call:
foo = _.partial(foo, 'bar', _, _, 'qux');
I am not necessarily remending that you use this, but at least you could take a look at their code and get some hints.
If you want to have predetermined arguments always e at the end, like 'qux'
, you will need some additional machinery. For instance, here's a little routine (using ES6, but you can adapt), that transforms a function into one where specified parameters are placed at the end of the argument list:
function partialEnd(fn, ...predefinedArgs) {
return function() {
return fn.apply(this, [...arguments, ...predefinedArgs]);
};
}
You can use this like this:
function foo(a, b, c) { console.log(a + b + c); }
foo = partialEnd(foo, 3);
foo(1, 2) // outputs 6
You could bine this with _.partial
using _
placeholders to obtain an effect where some parameters are inserted into the argument list, and others are always placed at the end:
function foo(arg1, arg2, arg3, arg4) { console.log(arguments); }
foo = _.partial(foo, 'bar', _, _);
foo = partialEnd(foo, 'lel');
foo('baz', 'lel');
> { '0': 'bar', '1': 'baz', '3': 'lel', '4': 'qux'}
No such functionality exists in JavaScript, but it would be fairly straightforward to implement a function that does the same thing:
function curryWithNulls(fn, thisObj) {
var curriedArgs = Array.prototype.slice.call(arguments, 2);
var length = curriedArgs.length;
return function() {
var args = Array.prototype.slice.call(arguments);
for (var i = 0; i < length || args.length; i++) {
if (i >= length || curriedArgs[i] === null) {
curriedArgs[i] = args.shift();
}
}
return fn.apply(thisObj, curriedArgs);
}
}
function foo(arg1, arg2, arg3, arg4) {
console.log(arguments);
}
var curriedFoo = curryWithNulls(foo, this, 'bar', null, null, 'qux');
curriedFoo('baz', 'lel');
// => { '0': 'bar', '1': 'baz', '2': 'lel', '3': 'qux' }
This differs slightly from your example in that it requires a null
for each skipped argument (whereas in your example you have a single null
fill in for two arguments). This allows more plex constructions with curried arguments in any position, e.g.:
var curriedFoo2 = curryWithNulls(foo, this, null, 'bar', null, 'qux');
curriedFoo2('baz', 'lel');
// => { '0': 'baz', '1': 'bar', '2': 'lel', '3': 'qux' }
No, you'd just be binding the null
.
The function's parameters are the function's parameters; binding a null
does exactly that, it doesn't redefine the function, it returns a new one with the same signature.
It is possible with a functional position:
var foo = function(arg1, arg2, arg3, arg4) { console.log(arguments); }
var bar = function(arg2, arg4) {
return foo.bind(this, 'bar', arg2, 'qux')();
}
bar('baz', 'lel');
or, with modern syntax:
const foo = (arg1, arg2, arg3, arg4) => console.log(arguments);
const bar = (arg2, arg4) => foo.bind(this, 'bar', arg2, 'qux')();
bar('baz', 'lel');
or without bind at all:
const foo = (arg1, arg2, arg3, arg4) => console.log(arguments);
const bar = (arg2, arg4) => foo(this, 'bar', arg2, 'qux', arg4);
bar('baz', 'lel');
P.S. Don't forget to call your binded function (note these () after bind);