使用带有参数数组的Function.prototype.bind?

Dan*_*nce 47 javascript functional-programming partial-application promise

如何使用参数数组调用Function.prototype.bind,而不是硬编码参数?(不使用ECMA6,因此没有传播运营商).

我试图在使用回调的模块周围放置一个promises包装器,我想绑定传递给我的包装器方法的所有参数并绑定它们.然后我想用我自己的回调调用部分应用的绑定函数,它将解析或拒绝一个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;
}
Run Code Online (Sandbox Code Playgroud)

但显然这不起作用,因为bind需要参数而不是参数数组.我知道我可以通过将我的回调插入到arguments数组的末尾并使用apply来做到这一点:

arguments[arguments.length] = function(err, docs) { ... }
db.find.apply(null, arguments);
Run Code Online (Sandbox Code Playgroud)

或者通过遍历arguments数组并为每个参数重新绑定函数:

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) { ... })
Run Code Online (Sandbox Code Playgroud)

但这两种方法都很脏.有任何想法吗?

Fel*_*ing 78

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

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

是否可以认为更清洁是留给读者的.

  • 一个小注释:[null] .concat(arguments)产生[null,arguments]因为参数不像数组那样对待.相反,这对我有用:var argsAsArray = Array.prototype.slice.call(arguments); bound = db.find.bind.apply(db.find,[null] .concat(argsAsArray)); (12认同)
  • 当然.太棒了!清洁概念,但在实践中?我想不是. (3认同)

Aad*_*hah 11

以下是我在所有项目中使用的常见代码片段:

var bind = Function.bind;
var call = Function.call;

var bindable = bind.bind(bind);
var callable = bindable(call);
Run Code Online (Sandbox Code Playgroud)

bindable函数现在可用于传递数组,bind如下所示:

var bound = bindable(db.find, db).apply(null, arguments);
Run Code Online (Sandbox Code Playgroud)

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

var findable = bindable(db.find, db);
var bound = findable.apply(null, arguments);
Run Code Online (Sandbox Code Playgroud)

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

var bound = findable(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • @torazaburo这并不重要,因为`Function`本身就是一个函数.因此,它从`Function.prototype`继承`bind`和`call`.因此,我使用了两种形式中较短的一种,因为......我是一个懒惰的虐待狂,喜欢用简洁的代码混淆人们. (4认同)
  • Bindable是绑定,绑定,绑定?我觉得有一首歌在流传. (2认同)

Joe*_*oel 9

Felix的回答对我不起作用,因为arguments对象实际上并不是一个数组(正如Otts指出的那样).我的解决方案是简单地切换bindapply:

bound = db.find.apply.bind(db.find, null, arguments);
Run Code Online (Sandbox Code Playgroud)

  • 如果写成`Function.apply.bind(db.find,null,arguments)`,我会发现它更容易理解.一般的`apply`方法必须执行`db.find`,上下文设置为`null`,arguments数组设置为`arguments`. (3认同)
  • 我发现这在概念上稍微有点困难(我想要一个绑定的函数调用,我有一个绑定的应用调用),但它有意义(我调用绑定应用,函数也被调用)并且在语法上更清晰:). (2认同)