普通视图

发现新文章,点击刷新页面。
昨天以前首页

JavaScript 中的 this 关键字

作者 riuphan
2026年5月27日 00:15

一、为什么需要 this?

  • this 是 js 中的一个关键字,它提供了一种更优雅的方式隐式地传递一个对象的引用,可以让代码更简洁

  • 如果没有 this,我们在编写面向对象的代码时,每一次都需要显式地将对象作为参数传入函数,这样不仅增加了代码的复杂度,也让复用和维护变得困难。

下面通过一个例子来直观感受 this 带来的便利。首先看没有使用 this 的写法:

function identify(context) {
    return context.name.toUpperCase();//将上下文中的name转换为大写
}

function speak(context) {
    var greeting = 'hello, I am ' + identify(context);
    console.log(greeting);
}

var me = { name: 'tom' };
speak(me); // 输出: hello, I am TOM

可以看到,每次调用函数都需要显式传递 context 对象。而使用 this 之后:

function identify() {
    return this.name.toUpperCase();
}

function speak() {
    var greeting = 'hello, I am ' + identify.call(this);
    console.log(greeting);
}

var me = { name: 'tom' };
speak.call(me); // 输出: hello, I am TOM

两段代码的输出结果完全相同,但第二种写法更加简洁,函数不再需要额外的参数context来接收对象,代码的复用性和可读性也更高。

二、this 可以出现在哪里?

this 的值取决于它出现的上下文:

  1. 全局作用域下this 指向 window 对象。例如在全局直接打印 this,得到的就是整个浏览器窗口对象。(Node.js下运行不同)

image.png

  1. 函数体内this 的指向取决于函数的调用方式,这是 this 最为复杂也最为重要的部分。

三、this 的绑定规则

1. 默认绑定

当一个函数被独立调用时(即直接调用函数,不依附于任何对象),函数内部的 this 指向 window 对象。这种情况称为默认绑定

var a = 1;
function foo(){
    console.log(this.a);
}
function bar(){
    var a = 2;
    foo(); // 独立调用,this 指向 window
}
bar();

当全局var a = 1时,相当于window.a = 1, 且this指向window,所以打印的是全局的a = 1

2. 隐式绑定

当一个函数被某个上下文对象所拥有,并通过该对象调用时,函数中的 this 会指向这个对象。这就是隐式绑定的核心含义。

function foo(){
    console.log(this);
}
var obj = {
    a: 1,
    foo: foo
};
obj.foo(); // this 指向 obj,打印 {a: 1, foo: f}

3. 隐式丢失

如果一个函数被多层对象引用并调用,this 只会指向距离函数最近的那个对象,这就是隐式丢失现象。

function foo(){
    console.log(this);
}
var obj = {
    a: 1,
    foo: foo
};
var oo = {
    a: 2,
    foo: obj
};
oo.foo.foo(); // this 指向 obj,而不是 oo

4. 显式绑定

有时候我们需要手动指定函数中 this 的指向,JavaScript 提供了三种方法来实现这一点:

  • call:立即调用函数,并指定 this 的值,可以逐个传递参数。
  • apply:与 call 类似,但参数必须以数组形式传递。
  • bind:不立即调用函数,而是返回一个新的函数,且参数可以分开传递
function foo(x, y){
    console.log(this.a, x + y);
}
var l = { a: 1 };

foo.call(l, 1, 2);          // this 指向 l,1和2是传递给函数的参数,打印 1 3
foo.apply(l, [1, 2]);       // this 指向 l,打印 1 3
const bar = foo.bind(l, 1); // 返回新函数,两个参数可以分开传递
bar(2);                      // this 指向 l,打印 1 3

5. new 绑定

使用 new 关键字调用构造函数时,函数内部的 this 会指向由 new 创建的实例对象。这是 JavaScript 实现面向对象编程的核心机制之一。

function Person(){
    this.name = '张三';
    this.age = 18;
}
const p = new Person(); // p 是 Person 构造函数的实例

new 的执行过程可以分解为以下步骤:

  • 创建一个空对象,var obj = {}
  • 将构造函数的 this 指向这个空对象,Person.call(obj)
  • 将空对象的原型指向构造函数的原型,obj.__proto__ = Person.prototype
  • 返回这个对象,return obj

四、箭头函数与 this

箭头函数是 ES6 引入的新语法,它与普通函数有一个关键区别:箭头函数没有 this 的概念。如果在箭头函数中使用 this,相当于是在外层第一个非箭头函数中的 this

function foo(){
    var fn = () => {
        this.a = 2; // this 相当于外层 foo 的 this
    }
    fn();
}
var obj = {
    a: 1,
    bar: foo
};
obj.bar();
console.log(obj.a); // 打印 2

解析:用obj调用,为隐式绑定,故foo的this指向obj,又因为箭头函数的 this 相当于外层 foo 的 this,所以this.a即obj.a,obj中a的值改为2,故打印2。

这个特性使得箭头函数在需要保持 this 上下文时非常有用,比如在回调函数中。同时也要注意,箭头函数不能用 new 关键字调用,因为它没有自己的 this 绑定机制。

❌
❌