function.apply.bind 在以下代码中是如何工作的?

Posted

技术标签:

【中文标题】function.apply.bind 在以下代码中是如何工作的?【英文标题】:How does function.apply.bind work in the following code? 【发布时间】:2017-02-15 20:12:42 【问题描述】:

所以我从 promise 返回了一个 [200,599] 数组,并且 spread 内部的回调函数被传递到 Function.apply.bind,但现在我迷路了。 [200,599] 的数组如何拆分为 x 和 y? apply.bind 究竟是如何工作的?

function getY(x) 
        return new Promise( function(resolve,reject)
            setTimeout( function()
                resolve( (3 * x) - 1 );
            , 100 );
         );
    

function foo(bar,baz) 
    var x = bar * baz;

    // return both promises
    return [
        Promise.resolve( x ),
        getY( x )
    ];


function spread(fn) 
    return Function.apply.bind( fn, null );


Promise.all(
    foo( 10, 20 )
)
.then(
    spread( function(x,y)
        console.log( x, y );    // 200 599
     )
)

【问题讨论】:

你知道他们自己做什么,对吧? 【参考方案1】:

.apply() 是函数对象的方法。像这样:

console.log(Math.max.apply(null, [1, 2, 3])); // 3

.apply() 接受两个参数,上下文(目标函数内部的 this)和一个可迭代的参数(通常是一个数组,但 arguments 数组也可以)。


.bind() 是函数对象的方法。像这样:

const x = 
  foo: function() 
    console.log(this.x);
  ,
  x: 42


var myFoo = x.foo.bind(x: 5);

x.foo(); // 42
myFoo(); // 5

.bind() 接受一个上下文(将成为this),以及可选的附加参数,并返回一个新函数,带有上下文绑定,并且附加参数被锁定


由于.apply()本身就是一个函数,所以可以和.bind()绑定,像这样:

Function.prototype.apply.bind(fn, null);

这意味着.apply()this 将是fn.apply() 的第一个参数将是null。这意味着它看起来像这样:

fn.apply(null, args)

这将从数组中传播参数。

【讨论】:

【参考方案2】:

Spread 接受一个函数并将binds 和apply method 应用于,部分应用null 参数。简而言之,

spread(fn)

转化为

args => fn.apply(null, args)

这与使用 ES6 扩展语法相同

args => fn(...args)

函数名称的来源。


如果您想要长答案,请记住 bind 的作用:

method.bind(context, ...args1)

返回一个类似的函数

(...args2) => method.call(context, ...args1, ...args2)

在我们的例子中,methodapplycontextfn,第一个参数是 null,所以调用

Function.apply.bind( fn, null )

将创建一个类似的函数

(...args2) => (Function.apply).call(fn, null, ...args2)

这相当于上面的fn.apply(…) 调用,因为apply 是两个访问中从Function.prototype 继承的方法。

【讨论】:

很好的解释,我不明白这修复了null 的第一个apply 参数,但是为什么我们需要这样做,是否有任何真正有用的情况,这可能会有所帮助! @SaherElgendy 不知道你在问什么。 apply 需要第一个参数,你还会传递什么?如果您询问 spread 函数的有用性,这在 ES6 的 rest/spread 语法中大部分已被弃用。 你的意思是Function.apply.bind( fn, null )这部分只是表达扩展语法的老方法? @SaherElgendy spread 是一个高阶函数,基本上是一个装饰器,围绕着被调用的函数。我们只使用function([x, y]) … ,而不是写spread(function(x,y) … ) 当然,但是spread(function(x,y) … )function(arr) var x = arr[0], y = arr[1]; … 更“实用”。【参考方案3】:

spread 函数只是一个实用函数,用于将数组转换为传递给函数的参数。 apply 进行转换,bind 将其绑定到调用函数,以便“this”上下文连接到同一个函数。

以更简单的形式查看传播如何运作 ->

spread(function (x,y)console.log(x,y);)([1,2])

你会得到答案,1 2,因为 1 被传递给 x,2 被传递给 y。

因此,在您的示例中,您的 promise.all 将返回一组已解决的承诺。 然后将它们映射到函数(x,y)的参数。

【讨论】:

【参考方案4】:

它起作用的原因是 apply 的“解构”性质(如果给定一个值数组,它们将被提供到您使用的函数上 apply)。

现在回到你的代码,当在 apply 上调用 bind 时,返回的值是一个函数,它返回提供给 bind 的相同函数,唯一不同的是在执行时它将使用 apply 调用(带有一个数组就像你的情况下的 thisArg 一样),但在你调用它之前它不会被执行。 在您的情况下,当承诺已解决时,提供给then woule 的函数将使用Promise 分辨率提供的参数数组执行。

function spread(fn)
   let boundedFn = fn.bind(fn)

   return function(arg)
      return boundedFn.apply(null,arg)
   

   
spread((x, y, c) => console.log(x, y, c))([1,2,3])

// or

Promise.resolve([6, 5]).then(spread((a, b) => console.log(a, b)))

之所以提供bind(在您的代码中)将null 作为第二个参数是为了防止将调用者提供的数组作为其第一个参数提供给apply,该参数为this 保留。

【讨论】:

以上是关于function.apply.bind 在以下代码中是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

指针 (*) 如何在以下代码中进行更改?

运行以下代码时,在 .remove() 方法中抛出 UnsupportedOperationException [重复]

Java:在以下代码中使用命令模式

如何在以下代码中停止调整大小和裁剪?

Discord.js - 在以下代码中更新 MessageEmbed

为啥我尝试在真实设备中运行代码时出现以下错误?