javascript 将 Function.prototype.bind 与参数数组一起使用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21507320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 21:03:03  来源:igfitidea点击:

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

javascriptfunctional-programmingpromisepartial-application

提问by Dan Prince

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

如何使用参数数组调用 Function.prototype.bind,而不是硬编码参数?(不使用 ECMA6,所以没有扩展运算符)。

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.

我正在尝试在使用回调的模块周围放置一个 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:

但显然这不起作用,因为 bind 需要参数而不是参数数组。我知道我可以通过将我的回调插入到参数数组的末尾并使用 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?

但是这两种方法都感觉很脏。有任何想法吗?

回答by Felix Kling

.bindis a normal function, so you can call .applyon it.
All you have to do is pass the original function as the first param and the desired THISvariable as the first item in the array of arguments:

.bind是一个正常的函数,所以你可以调用.apply它。
您所要做的就是将原始函数作为第一个参数传递,并将所需THIS变量作为参数数组中的第一项传递:

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

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

这是否可以被认为更清晰取决于读者。

回答by Aadit M Shah

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 bindablefunction can now be used to pass an array to bindas follows:

bindable函数现在可用于将数组传递给bind如下:

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:

事实上,您可以缓存bindable(db.find, db)以加速绑定,如下所示:

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

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

您可以使用findable带有或不带有参数数组的函数:

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

Hope this helps.

希望这可以帮助。

回答by Joel

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

Felix 的回答对我不起作用,因为该arguments对象并不是真正的数组(正如 Otts 指出的那样)。我的解决方案是简单地切换bindapply

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

回答by nathancahill

For those using ES6, Babel compiles:

对于那些使用 ES6 的人,Babel 编译:

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.

我认为可以公平地说 Babel 是非常确定的。不过,归功于@lorenz-lo-sauer,它几乎是相同的。

回答by Pawe?

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
}

回答by Lorenz Lo Sauer

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

回答by brillout

I find following cleaner than the accepted answers

我发现以下比接受的答案更清晰

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

回答by Matt Way

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?

为什么不按照您的示例简单地绑定到参数数组,并让bound()函数将其视为数组

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.

从您的用法来看,然后您将一个函数作为最终参数bound()传递给,这意味着通过传递实际参数数组,您不必将参数与 内部的回调分开bound(),这可能使其更容易使用。

回答by Dan Prince

Just had an alternative idea, partially apply the nullvalue for context and then use applyto call the partially applied function.

刚刚有了一个替代想法,部分应用null上下文的值,然后使用它apply来调用部分应用的函数。

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

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

这消除了@Felix[null].concat()答案中略显阴森的外观的需要。

回答by 131

A definitive and simple answer might be

一个明确而简单的答案可能是

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

Kinda "hard" to grasp, yet, neat.

有点“难”掌握,但是,整洁。