call底层逻辑是临时挂载函数到目标对象并立即清理:先包装thisarg为对象,再用symbol添加临时属性绑定函数,接着调用,最后删除属性;它仅影响当次执行,不改变函数本身。

显式绑定 call 的底层逻辑,核心就一句话:把函数临时挂到目标对象上,再调用它,调完立刻清理。它不改函数本身,也不留后遗症,只在“这一次”执行时强行让 this 指向你指定的对象。
call 做了哪几件事?
它内部大致按这四步走:
- 检查传入的
thisArg:如果不是对象(比如是null、undefined、数字或字符串),就用Object()包装成对应包装对象(如42 → new Number(42)) - 给这个目标对象临时加一个唯一属性(常用
Symbol()避免覆盖已有方法),值就是当前函数(即this) - 通过
目标对象.临时属性()执行函数——此时函数内的this自然指向目标对象 - 立即删掉那个临时属性,防止污染目标对象
为什么说它是“临时挂载”?
比如有函数 function fn() { console.log(this.x); } 和对象 const obj = { x: 100 };:
-
fn.call(obj)并不是真的把fn放进obj里永久保存 - 而是在运行时悄悄做:
obj[Symbol()] = fn; obj[Symbol()](); delete obj[Symbol()]; - 整个过程对
obj是无感的,外部查不到新增属性,也不会影响后续使用
几个关键细节不能忽略
这些地方容易出错,也最能体现底层逻辑:
-
thisArg为null或undefined时:非严格模式下自动转成全局对象(如window),严格模式下就真保持null/undefined - 参数传递是“展开”的:
fn.call(obj, 1, 2)相当于obj.fn(1, 2),不是把[1, 2]当一个参数传进去 - 箭头函数无法被 call 影响:因为它没有自己的
this,call再怎么绑也无效,只能沿用外层作用域的this - 只作用于当次调用:哪怕你写了
fn.call(obj),下一次直接fn(),this还是按默认规则来
和 apply 的区别只在参数处理
底层逻辑几乎一模一样,唯一的不同是:
-
call把后续所有参数逐个传给函数 -
apply要求第二个参数必须是数组或类数组(如arguments),然后用展开方式传入:fn.apply(obj, [1, 2])≡fn.call(obj, 1, 2)
不复杂但容易忽略。











