链接.apply()和.bind()令人惊讶的行为

时间:2018-08-16 14:47:41

标签: javascript ecmascript-6

我需要您的帮助才能更好地理解以下行为。

在下面的代码段中,我们可以看到fooBar输出foothis,然后按预期输出returns bar 1, 2, 3-意味着bar被{{ 1}}作为上下文。

foo

现在我们改为使用const arguments = [1,2,3]; function bar(...args) { console.log('bar this ->', this); return 'bar ' + args; } function foo(...args) { console.log('foo this ->', this); return 'foo ' + args; } const fooBar = bar.bind(foo, null)(arguments); console.log(fooBar); // <--- no surprises!

const bar = Math.max.apply;

在这种情况下,调用const arguments = [1,2,3]; const bar = Math.max.apply; function foo(...args) { console.log('foo this ->', this); return 'foo ' + args; } const fooBar = bar.bind(foo, null)(arguments); console.log(fooBar); // <--- surprise!而不是foo。为什么?在这种情况下,bar到底在做什么?我假设应该再次以bind()作为上下文来调用bar。在这种情况下,上下文为foo

我一直认为 someFunction.apply(someContext,args) 表现为 someFunction.bind(someContext,null)(args),但是在第二个示例中, someFunction.bind(someContext,null)(args) 表现为 someContext(args)

3 个答案:

答案 0 :(得分:1)

bind正在创建一个新函数,该函数调用其this值(bar,它是apply的副本),并将您作为新值传递给它的值this值。

由于barapply的副本:

bar.bind(foo)()foo.bar()foo.apply()相同。

答案 1 :(得分:1)

这是由于apply的特定目的:调用给定函数。请记住,bar是通用的Function.prototype.apply函数。

bind本质上是使用上下文(this值)和(可选)预设的参数创建原始函数的副本。 bind的polyfill将在内部使用apply

所以fooBar = bar.bind(foo, null)

相同
function fooBar(...args) {
    return Function.prototype.apply.apply(foo, [null, args]);
}

apply的双重使用显然令人困惑!

让我们逐步完成bar.bind(foo, null)(arguments)的操作:

Function.prototype.apply.bind(foo, null)(arguments)

可以减少为

Function.prototype.apply.apply(foo, [null, arguments])

在此特定情况下与

相同
foo(null, ...arguments);

之所以如此令人困惑,是因为您正在对apply函数进行复杂的调用,该函数是为函数的复杂调用而设计的!

答案 2 :(得分:1)

让我们进行模仿本地myApply的“临时” Function#apply,以更好地了解Function#apply的工作方式。

Function.prototype.myApply = function(args) {
    // some checks should be here to see if 'this' is a function and if 'args' is an array-like
    this(...args);
}

它需要一个包含参数的数组(或类似数组的对象),并调用this(适用于myApply的任何对象),该数组应该是一个函数,其中传递了args中的每一项作为独立参数。

简单示例:

现在,当您这样做时:

alert.myApply(["hello, there"]);

alert作为this传递给myApply(不言而喻),而["hello, there"]作为args传递,一切正常。

令人困惑的示例:

现在,当您使用thismyApply甚至bind来显式设置call的{​​{1}}的{​​{1}}时,

apply

var myApply = alert.myApply; var newFunction = myApply.bind(foo); 成为新函数(等效于绑定到newFunciton的{​​{1}}的函数)。调用myApply就像调用foo并将newFunction设置为myApply的{​​{1}}一样。调用this时,将调用其foo值(在这种情况下为myApply)。

附加说明:如您所见,this不会混淆其foo(它是一个函数)的上下文,因此该函数将被调用不论调用myApply之前的上下文如何,在此特定示例中,它都是全局对象thismyApply的{​​{1}}是window)。