Skip to content

04. JavaScript 中 this 指向的 7 种典型场景解析

1. 普通函数调用模式

在独立调用的普通函数中(非严格模式):

javascript
function showThis() {
  console.log(this); // 指向 window/global
}
showThis(); // 浏览器环境输出 Window 对象

严格模式下的差异:

javascript
"use strict";
function strictThis() {
  console.log(this); // undefined
}
strictThis();

2. 箭头函数特性

箭头函数的 this 继承自词法作用域:

javascript
const obj = {
  value: 42,
  regular: function() {
    setTimeout(function() {
      console.log(this.value); // undefined(普通函数)
    }, 100);
  },
  arrow: function() {
    setTimeout(() => {
      console.log(this.value); // 42(继承外层函数 this)
    }, 100);
  }
};
obj.regular();
obj.arrow();

类属性中使用箭头函数的典型案例:

javascript
class Counter {
  count = 0;

  increment = () => {
    this.count++; // 始终绑定实例
  };
}

const counter = new Counter();
const btn = document.querySelector('button');
btn.addEventListener('click', counter.increment); // this 正确指向实例

3. 对象方法调用

当函数作为对象方法调用时:

javascript
const person = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, ${this.name}!`);
  }
};

person.greet(); // "Hello, Alice!"
const greetFn = person.greet;
greetFn(); // "Hello, undefined!"(丢失上下文)

4. 构造函数模式

使用 new 关键字时:

javascript
function Car(make) {
  this.make = make;
  console.log(this instanceof Car); // true
}

const myCar = new Car('Tesla');

5. 显式绑定方法

通过 call/apply/bind 改变指向:

javascript
function introduce(lang) {
  console.log(`${this.name} codes in ${lang}`);
}

const dev1 = { name: 'Bob' };
const dev2 = { name: 'Eve' };

introduce.call(dev1, 'JavaScript'); // Bob codes in JavaScript
introduce.apply(dev2, ['Python']); // Eve codes in Python

const boundFn = introduce.bind(dev1);
boundFn('Java'); // Bob codes in Java

6. Class 语法中的表现

类方法与箭头函数的对比:

javascript
class Timer {
  constructor() {
    this.seconds = 0;
  }

  // 普通方法
  start() {
    setInterval(function() {
      this.seconds++; // 错误的 this 指向
    }, 1000);
  }

  // 正确解决方案 1:箭头函数
  startFixed1() {
    setInterval(() => {
      this.seconds++; // 正确指向实例
    }, 1000);
  }

  // 正确解决方案 2:bind
  startFixed2() {
    setInterval(function() {
      this.seconds++;
    }.bind(this), 1000);
  }
}

const t = new Timer();
t.startFixed1();

静态方法中的 this

javascript
class MyClass {
  static staticMethod() {
    console.log(this === MyClass); // true
  }
}
MyClass.staticMethod();

7. 事件处理函数

DOM 事件处理中的典型情况:

javascript
button.addEventListener('click', function() {
  console.log(this); // 指向 button 元素
});

// 错误示范
button.addEventListener('click', () => {
  console.log(this); // 继承外层 this(可能是 window)
});

判断 this 的流程图(Mermaid)

记忆公式

对于任意函数 fthis 指向,可以表示为:

this={newInstanceif new f()contextif f.call/apply/bind(context)lexicalThisif arrow functioncallerif obj.f()global/undefinedotherwise\text{this} = \begin{cases} \text{newInstance} & \text{if } \mathbf{new}\ f() \\ \text{context} & \text{if } f.\text{call/apply/bind}(context) \\ \text{lexicalThis} & \text{if arrow function} \\ \text{caller} & \text{if } \text{obj}.f() \\ \text{global/undefined} & \text{otherwise} \end{cases}

掌握这些规则后,建议通过以下步骤分析:

  1. 查看函数调用方式
  2. 确认是否使用箭头函数
  3. 检查是否通过对象调用
  4. 查看是否存在显式绑定
  5. 最后判断默认绑定情况