Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Function.prototype.bind with an array of arguments?

How can I call Function.prototype.bind with an array of arguments, as opposed to hardcoded arguments? (Not using ECMA6, so no spread operator).

I'm trying to put a promises wrapper around a module that uses callbacks and I want to bind all of the arguments passed in to my wrapper method and bind them. Then I want to call the partially applied bound function with my own callback, which will resolve or reject a promise.

var find = function() {
  var deferred, bound;
  deferred = Q.defer();
  bound = db.find.bind(null, arguments);
  bound(function(err, docs) {
    if(err) {
      deferred.fail(err);
    } else {
      deferred.resolve(docs);
    }
  });
  return deferred.promise;
}

But obviously this doesn't work because bind expects arguments rather than an array of arguments. I know I could do this by inserting my callback onto the end of the arguments array and using apply:

arguments[arguments.length] = function(err, docs) { ... }
db.find.apply(null, arguments);

Or by iterating over the arguments array and rebinding the function for each argument:

var bound, context;
for(var i = 0; i < arguments.length; i++) {
   context = bound ? bound : db.find;
   bound = context.bind(null, arguments[i]);
}
bound(function(err, docs) { ... })

But both of these methods feel dirty. Any ideas?

like image 390
Dan Prince Avatar asked Feb 02 '14 05:02

Dan Prince


People also ask

What is function prototype bind?

prototype. bind() The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

How do you bind an argument in JavaScript?

The full syntax of bind : let bound = func. bind(context, [arg1], [arg2], ...); It allows to bind context as this and starting arguments of the function.

What does bind () do in JavaScript?

bind is a method on the prototype of all functions in JavaScript. It allows you to create a new function from an existing function, change the new function's this context, and provide any arguments you want the new function to be called with.

When would you use the bind function?

The bind method creates a new function from another function with one or more arguments bound to specific values, including the implicit this argument.


3 Answers

.bind is a normal function, so you can call .apply on it.
All you have to do is pass the original function as the first param and the desired THIS variable as the first item in the array of arguments:

bound = db.find.bind.apply(db.find, [null].concat(arguments)); //      ^-----^            ^-----^   THIS 

Whether that can be considered cleaner or not is left to the reader.

like image 170
Felix Kling Avatar answered Oct 12 '22 04:10

Felix Kling


The following is a common snippet of code I use in all my projects:

var bind = Function.bind; var call = Function.call;  var bindable = bind.bind(bind); var callable = bindable(call); 

The bindable function can now be used to pass an array to bind as follows:

var bound = bindable(db.find, db).apply(null, arguments); 

In fact you can cache bindable(db.find, db) to speed up the binding as follows:

var findable = bindable(db.find, db); var bound = findable.apply(null, arguments); 

You can use the findable function with or without an array of arguments:

var bound = findable(1, 2, 3); 

Hope this helps.

like image 37
Aadit M Shah Avatar answered Oct 12 '22 04:10

Aadit M Shah


Felix's answer didn't work for me because the arguments object isn't really an array (as Otts pointed out). The solution for me was to simply switch bind and apply:

bound = db.find.apply.bind(db.find, null, arguments);
like image 34
Joel Avatar answered Oct 12 '22 06:10

Joel