有没有一种方法可以创建一个绑定函数,在数组中提供它的参数?

Is there a way to create a bound function providing it's arguments inside an array?

本文关键字:数组 参数 一个 方法 一种 创建 绑定 有没有 函数      更新时间:2023-09-26

假设我有一个如下的函数:

var func = function(a, b, c) {
    console.log(a);
    console.log(b);
    console.log(c);
}

我要做的是通过在数组中提供参数来调用它,就像这样:

func.apply(null, [1, 2, 3]);

按预期工作。现在,如果我想异步调用那个函数,比如使用setTimeout,我该怎么做呢?我尝试了以下操作:

setTimeout(func.bind.apply(null, [null, 1, 2, 3]), 1000);

但是它给了我一个错误:

TypeError: Bind必须在函数

上调用

是否有一种优雅的方式来做到这一点?

有很多方法可以做到这一点。

方法一:setTimeout附加参数

你知道你可以给setTimeout传递额外的参数,就像你可以对call做的那样吗?

setTimeout(func, 1000, 1, 2, 3);

但是假设你有一个参数数组:

setTimeout(func, 1000, [1, 2, 3]); // This will not work

所以你需要这样做:

setTimeout(function (args) {
    return func.apply(this, args);
}, 1000, [1, 2, 3]);

不幸的是,这在旧版本的Internet Explorer中不起作用。不过你也可以这样做:

function applyAsync(f, ms, args) {
    return setTimeout(function () {
        return f.apply(this, args);
    }, ms);
}

你可以这样调用它:

applyAsync(func, 1000, [1, 2, 3]);

在我看来,这是最干净和最快的解决方案。然而,如果你想要一个更聪明的解决方案,那么:

方法二:bindablecallableappliable

我最喜欢的JavaScript函数:

var bind = Function.prototype.bind;
var call = Function.prototype.call;
var apply = Function.prototype.apply;
var bindable = bind.bind(bind);
var callable = bindable(call);
var appliable = bindable(apply);

我不会详细解释它是如何工作的,但这是你需要知道的:

  1. bindable函数接受一个函数f,返回一个等价于f.bind的函数;和f.bind部分应用于任何附加参数。
  2. callable函数接受一个函数f,返回一个等价于f.call的函数;和f.call部分应用于任何附加参数。
  3. appliable函数接受一个函数f,返回一个等价于f.apply的函数;和f.apply部分应用于任何附加参数。

您要查找的函数是appliable:

setTimeout(appliable(func, null, [1, 2, 3]), 1000);

你可以选择

Function.apply.bind(func, null, [1, 2, 3])

Function.bind.apply(func, [null, 1, 2, 3])

当前你在null上应用bind,而不是func,这会抛出错误。

与其在Function上访问.apply/.bind,还不如使用Function.prototypefunc

您可以将参数传递给Function.prototype.bind本身,像这样

setTimeout(func.bind(null, 1, 2, 3), 1000);

在线演示

你得到的错误是因为bind将只操作一个函数对象,所以apply的第一个参数应该是实际的函数对象,像这样

setTimeout(func.bind.apply(func, [null, 1, 2, 3]), 1000);

你可以这样应用Function.prototype.bind,它只需要你传递null给你的数组的第一个元素,你应该是好的。

var myFun = function (a,b,c) {
    console.log(a,b,c);
}, myFunBound;
myFunBound = Function.prototype.bind.apply(myFun, [null, 1,2,3]);
setTimeout(myFunBound, 1000);