call的核心原理是临时挂载并立即执行:将函数挂到目标对象上以指定this执行,再删除临时属性,全程不修改原函数和原对象。

call 的核心原理不是“替换 this”,而是让函数在你指定的对象上**临时挂载并立即执行一次**——它不修改函数本身,也不改变目标对象,只在那一瞬间让函数体内的 this 指向你给的那个对象。
它实际做了四件事
以 fn.call(obj, a, b) 为例,内部大致按顺序完成:
- 把第一个参数
obj转成对象(如传null或42,会用Object()包装) - 在
obj上加一个临时属性(比如用Symbol()生成唯一键),值是fn - 调用
obj[临时键](a, b)—— 此时函数内this自然就是obj - 立刻删掉那个临时属性,
obj恢复原样,不留痕迹
为什么说它是“只读切换”?
整个过程对原函数和原对象都是无侵入的:
-
fn本身没被修改,也没被复制或重定义 -
obj只是短暂多了一个属性,执行完就清除,外部查不到、不影响后续使用 - 下一次直接调用
fn(),this还是按默认规则来,不受这次call影响
关键细节决定是否生效
有些情况看似用了 call,但 this 并没变,原因往往在这几个点:
- 箭头函数没有自己的
this,call传什么都无效,它永远沿用外层词法作用域的this - 用
new调用时,构造函数的this优先级高于call,Fn.call(obj)加上new,this仍指向新实例 - 传
null或undefined作第一个参数时:非严格模式下自动变成全局对象(如window),严格模式下就真保持null—— 建议显式传globalThis或具体对象,别依赖默认行为
和 apply 的区别只在参数传递
底层逻辑几乎一样,唯一不同是参数处理方式:
-
call(obj, a, b, c):后面参数逐个传入 -
apply(obj, [a, b, c]):第二个参数必须是数组或类数组,然后展开传入 - 两者效果等价:
fn.apply(obj, [1, 2])≡fn.call(obj, 1, 2)











