JavaScript 中 `this` 的用法

JavaScript 中的 `this` 关键字指的是执行一段代码的**上下文**。其值会根据使用地点和方式而变化。

关于此的要点

  • 动态:this 的值取决于执行上下文(如何以及在何处调用函数)。
  • 上下文相关:它可以指不同的东西,例如对象、全局对象或未定义。
  • 场景和行为

    1. 在全球范围内

    在全局执行上下文中:

  • 在浏览器中:this 指的是窗口对象。
  • 在 Node.js 中:this 指的是模块中的一个空的全局对象 ({})。
  • console.log(this); // Browser: window, Node.js: {}

    2. 函数内部

  • 在非严格模式下,this 指的是全局对象(例如浏览器中的窗口)。
  • 在严格模式下,这是未定义的。
  • // Non-strict mode
    function showThis() {
        console.log(this);
    }
    showThis(); // Browser: window, Node.js: global object
    
    // Strict mode
    "use strict";
    function showThisStrict() {
        console.log(this);
    }
    showThisStrict(); // Output: undefined

    3. 方法内部

    当函数是对象(方法)的属性时,“this”指的是拥有该方法的对象。

    const person = {
        name: "Alice",
        greet() {
            console.log(`Hello, my name is ${this.name}`);
        },
    };
    
    person.greet(); // Output: Hello, my name is Alice

    4. 在箭头函数中

    箭头函数没有自己的“this”。相反,它们从周围的(词汇)范围继承“this”。

    const person = {
        name: "Bob",
        greet: () => {
            console.log(`Hello, my name is ${this.name}`);
        },
    };
    
    person.greet(); // Output: Hello, my name is undefined
    // Because `this` in the arrow function refers to the outer global scope.

    为了避免出现问题,当您想要确保“this”保留封闭函数的上下文时,箭头函数很有用。

    5. 在构造函数或类中使用 this

    在构造函数或类中,“this”指的是正在创建的对象实例。

    class Person {
        constructor(name) {
            this.name = name;
        }
        greet() {
            console.log(`Hi, I'm ${this.name}`);
        }
    }
    
    const alice = new Person("Alice");
    alice.greet(); // Output: Hi, I'm Alice

    6. 在事件处理程序中

    在 DOM 事件处理程序中,“this”指的是触发事件的元素。

    document.getElementById("myButton").addEventListener("click", function () {
        console.log(this); // Output: 

    如果使用箭头函数,“this”将引用周围的范围,而不是元素。

    document.getElementById("myButton").addEventListener("click", () => {
        console.log(this); // Output: window (or undefined in strict mode)
    });

    使用 call、apply 和 bind 来改变这一点

    您可以使用“call”、“apply”或“bind”手动设置“this”。

  • call:调用一个函数并将其设置为第一个参数。
  • apply:类似于 call,但将参数作为数组。
  • bind:创建一个新函数,并将其绑定到指定的值。
  • function greet(greeting) {
        console.log(`${greeting}, my name is ${this.name}`);
    }
    
    const person = { name: "Charlie" };
    
    // Using call
    greet.call(person, "Hello"); // Output: Hello, my name is Charlie
    
    // Using apply
    greet.apply(person, ["Hi"]); // Output: Hi, my name is Charlie
    
    // Using bind
    const boundGreet = greet.bind(person, "Hey");
    boundGreet(); // Output: Hey, my name is Charlie

    常见问题

  • 丢失上下文:当将方法作为回调传递时,可能会丢失上下文。
  • const person = {
           name: "Dana",
           greet() {
               console.log(this.name);
           },
       };
    
       const greetFn = person.greet;
       greetFn(); // Output: undefined (global `this` in non-strict mode)

    **修复**:使用 `.bind()` 将 `this` 明确绑定到正确的上下文。

    const boundGreetFn = person.greet.bind(person);
       boundGreetFn(); // Output: Dana
  • 箭头函数误用:注意不要过度使用箭头函数,特别是在对象方法中,您可能需要方法自己的 this。
  • 概括

  • 这是对函数或块的执行上下文的动态引用。
  • 全局范围:this指的是全局对象(窗口或全局)。
  • 在方法内部:this 指的是拥有该方法的对象。
  • 箭头函数:这是词汇继承的(来自周围范围)。
  • 类/构造函数:这指的是正在创建的新对象。
  • 手动更改此项:使用 call、apply 或 bind。