javascript - Function.prototype.call.call 的 ECMAScript 算法
问题描述
众所周知的Function.prototype.call.call(func)
是一样Function.call.call(func)
的,一样的func()
这种技术从第一个浏览器开始就一直在起作用。因此,“双重调用”的算法可以很容易地从ES5 规范中推导出来
Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] )
当在一个带有参数thisArg和可选参数arg1、arg2等的对象func上调用 call方法时,将执行以下步骤:
- 如果IsCallable ( func ) 为 false,则抛出TypeError异常。
- 让argList为空List。
- 如果使用多个参数调用此方法,则以从arg1开始的从左到右的顺序将每个参数附加为argList的最后一个元素
- 返回调用func的[[Call]]内部方法的结果,提供thisArg作为this值,提供argList作为参数列表。
考虑一个简单的例子:
var func = function(){ console.log(42) };
Function.prototype.call.call(func);
提供此值.call.call(func)
的内部方法 [[Call]] 的调用也是如此。这怎么会导致调用?Function.prototype.call
func
func
看起来 [[Call]] 的内部方法.call
实际上调用了它的this值(如func.call()
)。但我没有从规范中得到它。
解决方案
[[Call]]
是所有函数对象的内部方法。它通过设置上下文和评估函数体来执行实际的函数调用。
来自ES5 规范:
13.2.1
[[Call]]
当使用 this 值和参数列表调用Function 对象F
[[Call]]
的内部方法时,将执行以下步骤:
- 假设funcCtx是使用F的
[[FormalParameters]]
内部属性的值、传递的参数 List args 和this值(如 10.4.3 中所述)为函数代码建立新执行上下文的结果。- 让 result 是评估FunctionBody的结果,它是F的
[[Code]]
内部属性的值。如果F没有[[Code]]
内部属性或其值为空 FunctionBody,则结果为(normal, undefined, empty)。- 退出执行上下文funcCtx,恢复之前的执行上下文。
- 如果result .type 被抛出,则抛出result .value。
- 如果返回结果.type,则返回结果.value。
- 否则结果.type 必须是正常的。返回未定义。
但是,请注意函数调用语法[[Call]]
也使用了它fn()
(查看第 8 步):
11.2.3 函数调用
产生 式 CallExpression : MemberExpression Arguments 的评估如下:
- 让 ref 是评估 MemberExpression的结果。
- 设 func 为 GetValue( ref )。
- 令 argList 为评估 Arguments的结果,生成参数值的内部列表(参见 11.2.4)。
- 如果 Type( func ) 不是 Object,则抛出 TypeError 异常。
- 如果 IsCallable 为 false,则抛出 TypeError 异常。
- 如果 Type( ref ) 是 Reference,那么
- 如果 IsPropertyReference( ref ) 为 true,则
- 让 thisValue 为 GetBase( ref )。
- 否则, ref的基础 是环境记录
- 让 thisValue 成为调用 GetBase( ref ) 的 ImplicitThisValue 具体方法的结果。
- 否则,Type( ref ) 不是参考。
- 让 thisValue 为 undefined。
- 返回调用func
[[Call]]
的内部方法 的结果,提供 thisValue 作为 this 值,并提供列表 argList 作为参数值。产生 式 CallExpression : CallExpression Arguments 的评估方式完全相同,除了包含的 CallExpression 在步骤 1 中评估。
推荐阅读
- amadeus - 自助服务生产中飞行灵感搜索失败
- c++ - 如何在 C++ 中下载带有不使用 libcurl 的参数的文件
- sparql - 如何在一次查询中获取属性标签
- android - 在谷歌地图中添加标记时,IONIC V4 应用程序关闭
- python - 如何在 alembic 升级中使用 op.execute
- arrays - 如何在本机反应中渲染对象?
- linux - 在 MAC 上安装 bcftools 时如何解决此错误?C 的问题:[ploidy.o] 错误 1
- python - 当您需要不同的参数时,如何在类中使用 if/elif?
- c# - C# WebBrowser HTML Get ByClass 不起作用
- google-cloud-platform - 如何获取在 Google Cloud Repositories 中推送新修改的历史信息?