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

怎甘沉沦 提交于 2019-11-28 04:50:50
Felix Kling

.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.

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.

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);

For those using ES6, Babel compiles:

db.find.bind(this, ...arguments)

to:

db.find.bind.apply(db.find, [this].concat(Array.prototype.slice.call(arguments)));

I think it's fair to say Babel is pretty definitive. Credit to @lorenz-lo-sauer though, it's almost identical.

Why not simply bind to the arguments array as per your example, and have the bound() function treat it just like that, as an array?

By the looks of your usage, you are then passing in a function as the final argument to bound(), which means by passing in the actual argument array, you avoid having to separate arguments from callbacks inside bound(), potentially making it easier to play with.

Generically, this schema suffices:

//obj = db
//fnName = 'find'
var args = [this||null].concat(Array.prototype.slice.apply(arguments);
obj[fnName].bind.apply(obj[fnName], args);

I find following cleaner than the accepted answers

Function.bind.apply(db.find, [null].concat(arguments));

If someone is looking for an abstract sample:

var binded = hello.apply.bind(hello,null,['hello','world']);

binded();

function hello(a,b){
  console.log(this); //null
  console.log(a); //hello
  console.log(b); //world
}

Just had an alternative idea, partially apply the null value for context and then use apply to call the partially applied function.

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

This removes the need for the slightly spooky looking [null].concat() in @Felix's answer.

A definitive and simple answer might be

Function.apply.bind(this.method, this, arguments);

Kinda "hard" to grasp, yet, neat.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!