Function.prototype.call.call双重调用等价于func()的运行原理解析
执行逻辑推导
整个过程完全遵循ES5规范中Function.prototype.call的定义,没有特殊处理,我们可以把Function.prototype.call.call(func)拆分为两层call调用逐一拆解:
- 第一层调用:确定
call的执行主体Function.prototype.call.call(func)中,最后一个.call的调用主体是Function.prototype.call本身,你可以等价理解为:
const baseCall = Function.prototype.call; baseCall.call(func);
此时我们先套入call方法的规范执行步骤,这次调用中:
调用
call的对象是baseCall本身,传入的thisArg为目标函数func,无额外参数
- 校验
baseCall是可调用对象,校验通过- 初始化空参数列表
- 无额外参数,参数列表保持为空
- 调用
baseCall的[[Call]]内部方法,将thisArg(也就是目标函数func)作为this值传入,空参数列表作为执行参数
- 第二层调用:执行
baseCall本身的逻辑
上一步触发了baseCall也就是Function.prototype.call的执行,此时baseCall运行时的this指向就是我们的目标函数func,再次套入call的规范执行步骤:
此时调用
call的对象就是目标函数func,没有传入显式的thisArg和额外参数
- 校验
func是可调用对象,校验通过- 初始化空参数列表
- 无额外参数,参数列表保持为空
- 调用
func的[[Call]]内部方法,this值为undefined(非严格模式下自动转为全局对象),空参数列表传入,也就是等价于直接执行func()
这就是整个操作最终触发func执行的完整逻辑。
等价性说明
Function.prototype.call.call(func)和Function.call.call(func)效果完全一致,是因为Function构造函数本身的call方法继承自Function.prototype.call,二者指向同一个函数,执行逻辑没有任何区别。
扩展验证
我们可以传入参数更直观验证逻辑:
const func = function(content) { console.log(`输出内容:${content || '默认值'}`) } // 等价于 func('测试') Function.prototype.call.call(func, undefined, '测试'); // 执行后输出:输出内容:测试
内容的提问来源于stack exchange,提问作者raiseman
相关产品推荐
相关产品推荐

