Skip to content

1. 核心概念 (Core Concept)

this 是 JavaScript 中的一个关键字,它在执行上下文中是一个特殊的对象引用。与词法作用域不同,this 的值是在函数被调用时才确定的(运行时绑定),而不是在函数定义时。它的指向完全取决于函数的调用方式 (call-site)

2. 为什么需要理解 this? (The "Why")

  1. 面向对象编程的基础: 在基于原型和类的面向对象编程中,this 是访问实例属性和方法的关键。错误地理解 this 会导致无法正确地操作对象状态。
  2. 解决常见的回调函数问题: 在回调函数(如事件处理器、定时器)中,this 的指向常常会丢失,导致非预期的行为。理解 this 的绑定规则是解决这类问题的核心。
  3. 掌握框架和库的原理: 许多框架(如 React 的类组件)和库都大量使用 this。理解其工作原理有助于更深入地使用这些工具,并能解决相关问题。
  4. this 是面试高频题: 对 this 指向的各种场景进行判断,是 JavaScript 面试中考察应聘者基础知识是否扎实的经典问题。

3. API 与用法 (API & Usage)

this 的指向主要遵循以下几种规则,优先级从低到高排列:

1. 默认绑定 (Default Binding)

当函数独立调用,且没有应用其他规则时,this 指向全局对象。在严格模式 ('use strict') 下,thisundefined

javascript
function sayHi() {
  console.log(this);
}

sayHi(); // 非严格模式: Window 对象
         // 严格模式: undefined

2. 隐式绑定 (Implicit Binding)

当函数作为对象的一个方法被调用时,this 指向调用该方法的对象。

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

user.greet(); // "Hello, Alice"。greet() 被 user 对象调用,this 指向 user。

隐式丢失: 如果将方法赋给一个变量后独立调用,this 会丢失其原始上下文。

javascript
const standaloneGreet = user.greet;
standaloneGreet(); // 非严格模式: "Hello, " (this 指向全局对象)
                   // 严格模式: TypeError (this 是 undefined)

3. 显式绑定 (Explicit Binding)

通过 call(), apply(), 或 bind() 方法,可以明确地指定函数调用时的 this 值。

  • call(thisArg, arg1, arg2, ...): 立即调用函数,this 绑定到 thisArg,参数逐个传递。
  • apply(thisArg, [argsArray]): 立即调用函数,this 绑定到 thisArg,参数以数组形式传递。
  • bind(thisArg): 立即调用函数,而是返回一个 this 被永久绑定到 thisArg 的新函数。
javascript
function introduce(city, country) {
  console.log(`I am ${this.name} from ${city}, ${country}.`);
}

const person = { name: 'Bob' };

introduce.call(person, 'New York', 'USA');   // "I am Bob from New York, USA."
introduce.apply(person, ['London', 'UK']); // "I am Bob from London, UK."

const introduceBob = introduce.bind(person);
introduceBob('Paris', 'France'); // "I am Bob from Paris, France."

4. new 绑定 (new Binding)

当使用 new 关键字调用一个函数(构造函数)时,会自动执行以下步骤:

  1. 创建一个全新的空对象。
  2. 这个新对象的 [[Prototype]] 被链接到构造函数的 prototype
  3. 这个新对象被绑定为函数调用的 this
  4. 如果函数没有返回其他对象,则 new 表达式会隐式返回这个新对象。
javascript
function Person(name) {
  this.name = name;
}

const alice = new Person('Alice');
console.log(alice.name); // "Alice"。在 Person 调用中,this 指向新创建的 alice 对象。

箭头函数 (=>) 的 this

箭头函数没有自己的 this 绑定。它会捕获其定义时所在上下文(词法作用域)的 this 值。this 的值在箭头函数定义时就已经确定,且之后无法通过 call, apply, bind 修改。

javascript
const obj = {
  name: 'My Object',
  regularMethod: function() {
    console.log(this.name); // 'My Object'

    // 箭头函数捕获了 regularMethod 的 this
    const arrowFunc = () => {
      console.log(this.name);
    };
    arrowFunc(); // 'My Object'
  },
  arrowMethod: () => {
    // 箭头函数在对象字面量中定义,捕获了定义时的全局 this
    console.log(this.name);
  }
};

obj.regularMethod();
obj.arrowMethod(); // 非严格模式下是全局 name (e.g., ""), 严格模式下 this 是 undefined

4. 关键注意事项 (Key Considerations)

  1. 优先级规则: new 绑定 > 显式绑定 (bind) > 隐式绑定 > 默认绑定。箭头函数的 this 不参与这个优先级比较,因为它在定义时就已固定。
  2. bind 的硬绑定: bind 创建的新函数,其 this 无法被后续的 callapply 修改(但 new 依然可以覆盖 bind 的绑定)。
  3. 回调函数中的 this 丢失: 在 setTimeout, 事件监听器等场景中,回调函数通常作为独立函数被调用,会触发默认绑定规则。这是箭头函数或 .bind(this) 最常见的应用场景。
  4. 严格模式的影响: 在严格模式下,默认绑定的 thisundefined 而不是全局对象,这有助于提早发现错误。

5. 参考资料 (References)

不知道说啥了很无语了