你还不了解JS中的this?

142 阅读2分钟

在 JavaScript 中,this 是一个至关重要且有些复杂的概念。它与函数的运行环境紧密相关,当我们对内存(栈内存和堆内存)有透彻的理解时,就能更好地把握 this 的行为机制。

首先,让我们回顾一些相关的概念,如调用栈、执行上下文、作用域以及作用域链(outer)。在这些概念体系中,其实还缺少一个指向函数调用对象的指针,而这个指针就是 thisthis 的值并非固定不变,它在函数执行的瞬间由函数的调用方式所决定

调用栈、执行上下文和作用域

JavaScript 代码的执行环境可以分为多个层次,包括全局执行上下文、函数执行上下文以及 eval 执行上下文等。每个执行上下文都有其对应的变量对象,而 this 就是在这个环境中指向某个特定对象的指针。

全局执行上下文

在全局执行上下文中,this 指向全局对象,在浏览器中就是 window 对象。

console.log(this === window); // true

函数执行上下文

当函数被执行时,会创建一个新的函数执行上下文,其中 this 的值由函数的调用方式决定。

对象的方法调用

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

var obj = {
    x: 1,
    foo: function() {
        console.log(this);
        console.log(this.x);
    }
};

obj.foo(); // 输出: {x: 1, foo: ƒ}, 1

普通函数调用

当函数作为普通函数被调用时,this 默认指向全局对象(非严格模式下),而在严格模式下则为 undefined

"use strict";

var x = 2;
var obj = {
    x: 1,
    foo: function() {
        console.log(this);
        console.log(this.x);
    }
};

// 提取方法到独立变量
var foo = obj.foo;

// 直接调用
foo(); // 输出: undefined, TypeError: Cannot read property 'x' of undefined

构造函数调用

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

function Person(name) {
    this.name = name;
}

var person = new Person("Alice");
console.log(person.name); // 输出: Alice

显式指定 this

还可以使用 callapplybind 方法显式地指定 this 的值。

var name = "刀郎";
var a = {
    name: "天外来物",
    func1: function() {
        console.log(this.name);
    },
    func2: function() {
        setTimeout(function() {
            // 使用 call 显式绑定 this 到对象 a
            this.func1.call(a);
        }, 1000);
    }
};

a.func2();

在这个例子中,setTimeout 内部的匿名函数默认情况下 this 指向全局对象。通过使用 .call(a) 我们可以将 this 绑定到对象 a 上,从而正确输出 "天外来物"

总结

  • 对象的方法调用this 指向该对象。
  • 普通函数调用:非严格模式下 this 指向全局对象;严格模式下 thisundefined
  • 构造函数调用this 指向新创建的对象实例。
  • 显式指定 this:可以通过 callapplybind 方法显式地指定 this 的值。

屏幕截图 2024-12-01 221630.png