5分钟搞懂:JS函数中的this到底应该指向谁?

114 阅读2分钟

JavaScript 中的 this 关键字是一个非常重要但有时会令人困惑的概念。它的值取决于函数的调用方式,而不是定义方式。在 ES5 中,我们经常需要控制 this 的指向,尤其是在异步编程和回调函数中。

1. this 的基本行为

在 JavaScript 中,this 的值通常取决于函数的调用方式:

  • 在全局范围内,this 指向全局对象(在浏览器中是 window)。
  • 当函数作为某个对象的方法调用时,this 指向那个调用者对象
  • 当函数作为构造函数使用,通过 new 关键字调用时,this 指向新创建的对象。
var num = 100
var obj = {
    num: 200,
    inner: {
        num: 300,
        print: function () {
            console.log(this.num)
        }
    }
}

obj.inner.print()

很明显,这段代码的输出结果是300,this指向了它的调用者inner

2. 使用 callapply 修改 this 的作用域

callapply 都用于调用函数,并允许你为函数的执行指定 this 的值。它们的不同之处在于如何传递参数:

  • call 方法接受一个参数列表。
  • apply 方法接受一个包含多个参数的数组。
function showDetails(age, job) {
    console.log(this.name + " is " + age + " years old and is a " + job + ".");
}

var person = {
    name: "John"
};

showDetails.call(person, 30, "developer");  // John is 30 years old and is a developer.
showDetails.apply(person, [30, "developer"]);  // John is 30 years old and is a developer.

3. 使用 bind 创建新函数

bind 方法创建一个新的函数,在这个新函数中 this 被指定为 bind 的第一个参数,其余参数将作为新函数的预设参数。

function greet(greeting) {
    console.log(greeting + ", " + this.name);
}

var person = {
    name: "John"
};

var greetPerson = greet.bind(person);
greetPerson("Hello");  // Hello, John

4. ES6 箭头函数与 this

ES6 引入了箭头函数,它们不仅语法更简洁,而且 this 的行为也与普通函数不同。箭头函数不绑定自己的 this,它们继承上一层作用域链中的 this 值。

var person = {
    name: "John",
    activities: ["coding", "reading", "gaming"],
    showActivities: function() {
        this.activities.forEach((activity) => {
            console.log(this.name + " likes " + activity);
        });
    }
};

person.showActivities();  // John likes coding
                           // John likes reading
                           // John likes gaming

小结

通过使用 callapplybind,我们可以在 JavaScript ES5 中灵活地控制函数的 this 指向。而 ES6 的箭头函数为我们处理 this 提供了更简洁有效的方式,特别是在嵌套函数和回调函数中。