call和apply不改变词法作用域,只重绑定函数执行时的this值;作用域链由定义位置决定且恒定,而this指向随调用方式动态变化。

JavaScript中通过call或apply调用函数时,并没有改变函数的**词法作用域(Lexical Scope)**,而是改变了函数执行时的**this绑定值(执行上下文中的this)**。这是关键区别——作用域本身不可变,变的是this指向的对象。
本质:替换函数调用时的this,而非作用域
函数定义时的作用域链(由函数声明位置决定)完全不变。所谓“改变作用域”是常见误解,准确说是“改变函数运行时的执行上下文”,核心就是重绑定this值:
-
fn.call(obj, a, b)→ 执行fn时,this === obj -
fn.apply(obj, [a, b])→ 同样让this === obj,仅参数传入形式不同 - 若不传第一个参数(或传
null/undefined),非严格模式下this指向全局对象(如window),严格模式下保持undefined
内部机制:临时赋予目标对象一个方法引用
引擎层面可理解为做了类似以下操作(非真实代码,仅为示意):
- 将待调用函数临时挂载到目标对象上,比如
obj._temp = fn - 以
obj._temp(a, b)方式执行,此时自然满足this === obj - 立即删除该临时属性,避免污染目标对象
这个过程不修改原函数的闭包、变量查找路径或外层作用域,只影响this在本次调用中的值。
为什么容易误以为“作用域变了”?
因为this常被用来访问对象属性(如this.name),而不同this导致读取到不同数据,给人“作用域切换”的错觉。例如:
const user = { name: 'Alice' };
const admin = { name: 'Bob' };
function greet() { return `Hello, ${this.name}`; }
greet(); // Hello, undefined(this指向全局,无name)
greet.call(user); // Hello, Alice(this指向user)
greet.call(admin); // Hello, Bob(this指向admin)
函数体内的this.name查找逻辑没变,变的只是this所指的对象。
与真正作用域相关的对比
真正的词法作用域由函数定义位置决定,不受call/apply影响:
- 内部能访问的外层变量(如闭包中的
var x = 10)始终不变 -
let/const块级作用域、函数参数、形参名绑定均不受影响 - 只有
this、arguments(非箭头函数)、new.target等执行期上下文相关值被重置
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











