如何理解JavaScript中的this关键字_JavaScript中this的指向如何确定

JavaScript 中的 this 指向函数被调用时的执行上下文对象,而非定义时所在对象;普通调用时非严格模式下为全局对象(浏览器中为 window),严格模式下为 undefined;对象方法调用时 this 指向该对象;箭头函数无自有 this,继承外层非箭头函数的 this;new、call、apply、bind 可显式控制 this。

JavaScript 中的 this 不是指“函数定义时所在的对象”,而是“函数被调用时的执行上下文对象”——这个判断必须在每次调用时动态计算,不能靠代码位置猜。

普通函数调用时的 this 指向全局或 undefined

在非严格模式下,直接调用函数(如 foo()),this 指向全局对象(浏览器中是 window);严格模式下是 undefined。这是最容易误判的场景。

常见错误现象:this 在回调里突然变成 windowundefined,尤其在事件监听、定时器、数组方法(如 mapforEach)中传入普通函数时。

  • 避免方式:用箭头函数(不绑定自己的 this)、显式绑定(bind/call/apply)、或改用对象方法调用形式
  • 注意 Node.js 环境中全局对象是 global,不是 window
  • ES Module 脚本默认启用严格模式,所以顶层普通函数调用的 thisundefined

对象方法调用决定 this 绑定到该对象

当函数作为对象属性被调用(如 obj.method()),this 指向 obj。但只看调用形式,不看函数如何定义或赋值。

const obj = {
  name: 'Alice',
  say() {
    console.log(this.name); // 'Alice'
  }
};
const fn = obj.say;
fn(); // this 是 undefined(严格模式),不是 obj!
obj.say(); // this 是 obj

关键点:

  • this 只由「谁点出来的」决定,不是「谁定义的」
  • 一旦把方法赋给变量(fn = obj.say),就丢失了调用主体,变成普通调用
  • 解构赋值也会触发相同问题:const { say } = obj; say(); 同样丢失 this

箭头函数没有自己的 this,继承外层作用域

箭头函数不创建自己的 this,它会沿作用域链向上查找最近的非箭头函数的 this 值。因此它无法通过 callapplybind 改变 this

const obj = {
  name: 'Bob',
  regular() {
    console.log(this.name); // 'Bob'
    const arrow = () => console.log(this.name); // 'Bob'
    arrow();
  }
};
obj.regular();

适用场景:

  • 避免在 setTimeoutPromise.thenaddEventListener 回调中手动 bind(this)
  • 类中定义事件处理器时(class X { handleClick = () => { ... } }
  • 但不要在需要动态 this 的地方用箭头函数,比如想让方法能被不同对象复用时

new 调用和 call/apply/bind 显式控制 this

new Fn() 会让 this 指向新创建的实例;Fn.call(obj, ...)Fn.apply(obj, [...])Fn.bind(obj) 则强制指定 this 值。

容易踩的坑:

  • bind 返回的是新函数,必须调用才生效:obj.method.bind(other)(),漏掉末尾 () 就没执行
  • callapply 立即执行,区别只在参数传法:call 用逗号分隔,apply 用数组
  • 箭头函数无法被 call/apply/bind 修改 this,传进去的值会被忽略

真正难的不是记住规则,而是意识到 this 的值永远取决于「函数怎么被调用」,而不是「函数怎么被写」。哪怕同一个函数,在不同调用形式下 this 可能完全不同。调试时别盯着函数体,先看调用表达式左侧是什么。