如果a是一个函数,那么`a.call.call`到底是做什么的?

11

这里输入图片描述

这些代码在Chrome开发工具中运行。

看起来,b.call(与a.call.call相同)调用第一个参数,即一个函数,然后将第二个参数作为this传入。 如果第一个参数不是一个函数,则抛出not a function错误。

有人能解释一下<Function>.call.call是如何工作的吗?


“文档领主”(也称为“NullReference”)尚未出现,因此在此之前,您的问题可能有些过于宽泛。在那之前,我建议您使用其他资源,例如MDN(https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/call)。 - Jeroen
@jeroen 我已经阅读了 MDN 上的文档,但那只是解释了 call 函数的工作原理,并给出了一些示例。我在这里确切地询问的是 call.call,它的行为与 call 不同。而且我无法理解 call.call 的工作原理。 - tjfdfs
1
.call() 的第一个参数是你想要在 call() 执行的函数中设置为 this 值的对象。如果 call() 本身就是要操作的函数,因为你已经链接了 .call.call(),那么它会如何处理提供的 this 值呢?它会假设它是一个函数并尝试调用它。但是你的最后一行代码没有传递一个函数,而是传递了一个空对象。 - nnnnnn
顺便提一下,你的 ba 没有任何关系:a 只是设置 b 引用 call 函数的机制的一部分。 - nnnnnn
2个回答

12

让我给你举个例子。

function a() { console.log(1) }

function b() { console.log(2) }

a.call(b)    // 1

a.call.call(b)    // 2

a.call.call.call(b)    // 2

为什么?

我们知道a.call(b)表示使用参数b调用a()函数。

因此,a.call.call(b)表示使用参数b调用Function.prototype.call()函数,与Function.prototype.call.call(b)相同。

但是Function.prototype.call.call()不是普通的函数对象。 它可以被调用,但它没有属性。 有一些独特的规则来调用它。

Function.prototype.call.call(a)    // 1

Function.prototype.call.call(b)    // 2

事实上,Function.prototype.call.call(b) 是一个异国情调对象,进一步说是一个绑定函数异国情调对象。

  • [规范] 绑定函数是包装另一个函数对象的异国情调对象。

  • [规范] 调用绑定函数通常会导致调用其封装的函数。

因此,Function.prototype.call.call(a) 简单地意味着 a()

a.call.call(x) 意味着调用 x,也就是 x()

  • [规范] 在 Function.prototype.call(thisArg) 中,如果 thisArg 为 undefined 或 null,则将其替换为全局对象。

a.call.call() 意味着 a.call.call(undefined) 意味着 a.call.call(window) 意味着调用 window

试图调用 window,你会得到 Uncaught TypeError: window is not a function,所以试图调用 a.call.call(),你会得到 Uncaught TypeError:a.call.call 不是函数

希望这可以帮助。


1
从基础开始,
什么是 .call?它是在 Function.prototype 内可用的函数。 因此,它可以在任何函数上调用,这正是您能够调用 a.call 的原因。
现在,.call 做什么?它在您调用 .call 的函数上设置 this 上下文。因此,在您的情况下,当您调用 a.call 时,它可以在函数 a 上设置一个 this 上下文(通过您传递给 .call 函数的第一个参数)。 .call 函数内部的 this 是什么?它就是您调用 .call 的函数(在您的情况下是 a), 因此,为了简单起见,您可以假设在 .call 中调用函数如 this() (即调用 a())- 到目前为止都很好。
回答您的问题:
a.call.call

这里发生了什么?第二个.call(我从左往右数)调用了第一个.call并为第一个.call设置了this,这只是第一个参数,也就是一个函数。
现在第一个.call将调用this()(请记住,这是由第二个.call设置的,并且它是您传递的第一个参数,这是一个函数)。
我希望我能解释清楚我的意思。
让我告诉你为什么你会对a.call.call感到困惑。这是因为你在想我的函数a在所有这些混乱中去哪了? 实际上,在你调用第二个.call时,this传递给第一个.call来自第二个.call,这使得你的函数a在这种情况下变得不必要。
在你的情况下,应该在 Function.prototype 或 Object 或任何其他函数上调用 .call.call(记住 .call 是 Function.prototype 的一部分,可以在任何函数上调用)。因此,你应该这样做:
Function.prototype.call.call(...)

或者甚至
Object.call.call(...)

上周我对这些事情感到困惑(不是.call.call而是.call.bind),我在这里提出了一个问题,有人非常详细地解释了这个问题,你可以在这里找到。

我试着从我提出的问题的理解来回答。

毕竟这就是SO的用途

更新:

你的问题是:“似乎b.call(与a.call.call相同)正在调用第一个参数,即函数,然后将第二个参数作为this传递。如果第一个参数不是函数,则抛出“不是函数”的错误。”

你的假设在这里是正确的


谢谢!我会仔细阅读您的答案和链接,以获取一些想法。 - tjfdfs
你的假设是正确的,我已经更新了我的答案以涵盖这一点。 - Oxi
请结合一个易于理解的例子来说明。 - Kaushik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接