深入理解JavaScript 中的 this

130 阅读2分钟

1. this 是什么?

在 JavaScript 中,this 关键字用于指向调用它的对象。但它的指向并不是在编写代码时确定的,而是在 函数执行时 决定的。


2. this 在不同场景下的表现

2.1 作为对象的方法调用

const obj = {
    name: 'Tom',
    sayHello() {
        console.log(this.name);
    }
};
obj.sayHello(); // Tom

解析this 指向 obj,因为 sayHello 是通过 obj 调用的。


2.2 直接调用函数(普通函数调用)

function show() {
    console.log(this);
}
show(); // 非严格模式下:window / 严格模式下:undefined

解析

  • 非严格模式下,this 指向全局对象 window
  • 严格模式下,thisundefined

2.3 构造函数调用

function Person(name) {
    this.name = name;
}
const p = new Person('Tom');
console.log(p.name); // Tom

解析this 指向新创建的实例 p


2.4 箭头函数中的 this

const obj = {
    name: 'Tom',
    sayHello: () => {
        console.log(this.name);
    }
};
obj.sayHello(); // undefined

解析

  • 箭头函数不会创建自己的 this,它的 this 继承自定义它的作用域。
  • 这里 this 指向的是全局对象 window(在严格模式下 undefined)。

正确写法(使用普通函数):

const obj = {
    name: 'Tom',
    sayHello() {
        console.log(this.name);
    }
};
obj.sayHello(); // Tom

2.5 this 丢失问题

class Person {
    constructor(name) {
        this.name = name;
    }
    sayHello() {
        console.log(this.name);
    }
}
const p = new Person('Tom');
const x = p.sayHello;
x(); // undefined

原因p.sayHello 只是一个函数的引用,它被赋值给变量 x,但 xp 没有任何关系了。 在 JavaScript 中,this 只在函数被调用时确定,而不是在函数定义时

所以这里this 指向 window(非严格模式)或 undefined(严格模式),

解决方案

  • 使用 bind 绑定 this

    const x = p.sayHello.bind(p);
    x(); // Tom
    
  • 使用箭头函数(继承 this

    const x = () => p.sayHello();
    x(); // Tom
    
  • 使用 call apply

    x.call(p); // Tom
    x.apply(p); // Tom
    

3. this 在事件处理程序中

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

注意:如果使用箭头函数,this 可能会指向 window 而不是按钮。

document.querySelector("button").addEventListener("click", () => {
    console.log(this); // this 指向 window,而不是按钮
});

解决方案:用普通函数代替箭头函数。


4. thissetTimeoutsetInterval

const obj = {
    name: 'Tom',
    sayHello() {
        setTimeout(function() {
            console.log(this.name);
        }, 1000);
    }
};
obj.sayHello(); // undefined

原因setTimeout 里的 this 指向 window(非严格模式)。

解决方案

  • 使用箭头函数(继承 this

    sayHello() {
        setTimeout(() => {
            console.log(this.name);
        }, 1000);
    }
    

5. thiscallapplybind

call apply (手动绑定 this 并立即执行)

function sayHello() {
    console.log(this.name);
}
const person = { name: 'Tom' };
sayHello.call(person); // Tom
sayHello.apply(person); // Tom

区别

  • call(thisArg, arg1, arg2, ...) 直接传参数。
  • apply(thisArg, [arg1, arg2, ...]) 以数组方式传参数。

bind (手动绑定 this ,但不会立即执行)

const boundFunc = sayHello.bind(person);
boundFunc(); // Tom

6. 总结

场景this 指向
对象方法调用调用它的对象
普通函数调用window(非严格模式)或 undefined(严格模式)
构造函数调用新创建的实例
箭头函数继承外层作用域的 this
事件处理程序绑定的 DOM 元素(普通函数)或 window(箭头函数)
setTimeout/setIntervalwindow(非严格模式)或 undefined(严格模式)
call/apply/bind绑定的对象

注意

  • 箭头函数不会创建自己的 this ,它会继承定义它的作用域的 this
  • 普通函数的 this 取决于调用方式,而不是定义位置
  • 手动绑定 this 可以用 bind call apply