【问题标题】:ECMAScript algorithm for Function.prototype.call.callFunction.prototype.call.call 的 ECMAScript 算法
【发布时间】:2021-12-03 00:02:22
【问题描述】:

众所周知Function.prototype.call.call(func)Function.call.call(func)相同,与func()相同

这种技术从第一个浏览器开始就一直有效。因此“双重调用”的算法可以很容易地从ES5 specification推导出来

Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] )
当对象 func 调用 call 方法时,使用参数 thisArg 和可选参数 arg1, arg2 等,采取以下步骤:

  1. 如果 IsCallable(func) 为 false,则抛出 TypeError 异常。
  2. argList 为空 List
  3. 如果使用多个参数调用此方法,则以从左到右的顺序从 arg1 开始将每个参数附加为 argList 的最后一个元素
  4. 返回调用func[[Call]]内部方法的结果,提供thisArg作为this em> 值和 argList 作为参数列表。

考虑一个简单的例子:

var func = function(){ console.log(42) };
Function.prototype.call.call(func);

所以.call.call(func)Function.prototype.call 的内部方法[[Call]] 的调用,提供func 作为this 值。这怎么会导致func的调用?

看起来.call 的[[Call]] 内部方法实际上调用了它的this 值(如func.call() 的情况)。但我没有从规范中得到它。

【问题讨论】:

  • 如果你对 ES5 规范没有过分痴迷,也许contemporary spec 在这种情况下会更直接。

标签: javascript ecmascript-6 ecmascript-5


【解决方案1】:

[[Call]] 是所有函数对象的内部方法。它通过设置上下文和评估函数体来执行实际的函数调用。

来自ES5 Specification

13.2.1 [[Call]]

当使用 this 值和参数列表调用 Function 对象 F[[Call]] 内部方法时,将执行以下步骤:

  1. funcCtx 成为使用 F[[FormalParameters]] 内部属性的值、传递的参数 List args 为函数代码建立新执行上下文的结果,以及 10.4.3 中描述的 this 值。
  2. 让 result 是评估 FunctionBody 的结果,它是 F[[Code]] 内部属性的值。如果 F 没有 [[Code]] 内部属性或者如果它的值为空 FunctionBody,则 result(normal, undefined, empty)
  3. 退出执行上下文funcCtx,恢复之前的执行上下文。
  4. 如果 result.type 是 throw 则抛出 result.value。
  5. 如果返回result.type,则返回result.value。
  6. 否则result.type 必须正常。返回未定义

但是,请注意 [[Call]] 也被 fn() 函数调用语法使用(请看第 8 步):

11.2.3 Function Calls

产生式 CallExpression : MemberExpression Arguments 评估如下:

  1. ref 为评估 MemberExpression 的结果。
  2. func 为 GetValue(ref)。
  3. argList 为评估 Arguments 的结果,生成参数值的内部列表(参见 11.2.4)。
  4. 如果 Type(func) 不是 Object,则抛出 TypeError 异常。
  5. 如果 IsCallable 为 false,则抛出 TypeError 异常。
  6. 如果 Type(ref) 是参考,那么
    1. 如果 IsPropertyReference(ref) 为 true,则
      1. thisValue 为 GetBase(ref)。
    2. 否则,ref 的基础是环境记录
      1. thisValue 为调用 GetBase(ref) 的 ImplicitThisValue 具体方法的结果。
  7. 否则,Type(ref) 不是参考。
    1. thisValueundefined
  8. 返回在func上调用[[Call]]内部方法的结果,提供thisValue作为this值并提供列表 argList 作为参数值。

产生式 CallExpression : CallExpression Arguments 是 以完全相同的方式进行评估,除了包含 CallExpression 在步骤 1 中进行评估。

【讨论】:

  • 好的,13.2.1 说:让 result 是计算 FunctionBody 的结果,它是 F 的 [[Code]] 的值。所以.call1.call2(func) 应该评估.call1 FunctionBody,但它确实评估了func 正文,即this 值。
  • 这要么是规范缺陷,要么是隐藏在 ECMAScript 文本深处的无形魔法。
  • @raiseman:很可能是这种行为在 ES5 规范中没有明确(或暗示),但新版本区分了用户定义的函数和内置函数(Function.prototype.call 是内置函数)。后者有不同的[[Call]] 实现:tc39.es/ecma262/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
  • 2015-09-27
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
相关资源
最近更新 更多