Skip to content

this 是 JavaScript 中一个非常重要且常用的关键字,它的值在不同的上下文中会有所不同。理解 this 的使用场景和区别对编写 JavaScript 代码非常重要。以下是 this 在不同场景中的使用及其区别:

1. 全局作用域中的 this

在全局作用域(非严格模式下),this 指向全局对象。在浏览器环境中,this 指向 window 对象;在 Node.js 中,this 指向 global 对象。

示例:

javascript
console.log(this); // 在浏览器中,输出 window

区别

  • 非严格模式 下,this 会默认指向全局对象。
  • 严格模式 下(通过 "use strict" 开启),this 会是 undefined
javascript
"use strict";
console.log(this); // 输出 undefined

2. 函数调用中的 this

当函数在非严格模式下直接调用时,this 默认指向全局对象 windowglobal

示例:

javascript
function sayHello() {
  console.log(this); // 在非严格模式下,输出 window
}
sayHello();

严格模式 下,this 将是 undefined

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

3. 对象方法中的 this

this 在对象的方法中使用时,this 指向调用该方法的对象。

示例:

javascript
const person = {
  name: "Alice",
  greet() {
    console.log(this.name); // this 指向 person 对象
  }
};
person.greet(); // 输出 "Alice"

区别

  • 在对象方法中,this 指向的是调用该方法的对象,而不是定义该方法的对象。

4. 构造函数中的 this

当使用构造函数创建对象时,this 指向新创建的对象实例。构造函数通过 new 关键字调用。

示例:

javascript
function Person(name) {
  this.name = name;
}
const alice = new Person("Alice");
console.log(alice.name); // 输出 "Alice"

区别

  • 在构造函数中,this 指向的是通过 new 生成的对象实例。

5. 箭头函数中的 this

箭头函数与普通函数不同,它的 this 是词法绑定的,指向函数定义时所在的上下文(即箭头函数声明时所处的作用域的 this),而不是调用时的上下文。

示例:

javascript
const person = {
  name: "Alice",
  greet: function() {
    const innerFunc = () => {
      console.log(this.name); // this 指向 person 对象
    };
    innerFunc();
  }
};
person.greet(); // 输出 "Alice"

在这个例子中,箭头函数 innerFunc 继承了 greet 方法中的 this,而 greet 方法中的 this 指向 person 对象。因此 innerFunc 中的 this.name 也是指向 person.name

区别

  • 普通函数的 this 是动态绑定的,取决于它是如何被调用的。
  • 箭头函数的 this 是静态绑定的,取决于它定义时的上下文,不会被调用方式所改变。

6. 事件处理中的 this

在事件处理函数中,this 默认指向触发事件的 DOM 元素。

示例:

javascript
const button = document.querySelector("button");
button.addEventListener("click", function() {
  console.log(this); // this 指向被点击的按钮元素
});

区别

  • 在普通函数中,事件处理函数的 this 指向触发事件的 DOM 元素。
  • 如果使用箭头函数作为事件处理函数,this 将继承自其外层作用域,而不会指向 DOM 元素。

示例(箭头函数):

javascript
const button = document.querySelector("button");
button.addEventListener("click", () => {
  console.log(this); // this 继承自外部作用域,可能是 window 或其他对象
});

7. callapplybind 中的 this

  • callapply: 这两个方法可以显式地设置函数中的 this 指向。它们的区别在于传参方式不同:
    • call(thisArg, arg1, arg2, ...)
    • apply(thisArg, [arg1, arg2, ...])

示例:

javascript
function greet() {
  console.log(this.name);
}
const person = { name: "Alice" };

greet.call(person);  // 输出 "Alice"
greet.apply(person); // 输出 "Alice"
  • bind: bind 方法会创建一个新的函数,并永久性地将 this 绑定到指定的对象。

示例:

javascript
function greet() {
  console.log(this.name);
}
const person = { name: "Alice" };

const boundGreet = greet.bind(person);
boundGreet(); // 输出 "Alice"

区别

  • callapply 是立即调用函数,并且可以动态指定 this
  • bind 是返回一个新的函数,this 永久绑定为指定的对象。

8. 在类中的 this

在类方法中,this 指向类的实例对象。

示例:

javascript
class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(this.name);
  }
}

const alice = new Person("Alice");
alice.greet(); // 输出 "Alice"

区别

  • 在类中,this 指向当前类的实例。

总结

场景this 的指向
全局作用域在非严格模式下,指向全局对象(浏览器中是 window,Node.js 中是 global);严格模式下是 undefined
普通函数调用在非严格模式下指向全局对象;严格模式下是 undefined
对象方法调用指向调用该方法的对象。
构造函数调用指向新创建的对象实例。
箭头函数this 绑定到定义时所在的词法作用域,而不是调用时的作用域。
事件处理函数指向触发事件的 DOM 元素。
callapplybind可以显式指定 this 的指向。
类方法中的 this指向类的实例对象。

总结

理解 this 的使用和行为对于编写健壮的 JavaScript 代码至关重要。this 的指向通常取决于它的调用方式,而不是它的定义方式。在使用箭头函数时,this 会继承自定义时的作用域,而在事件处理、普通函数调用中,this 的指向可能会发生不同的变化。在需要灵活指定 this 时,可以使用 callapplybind