一篇文章告诉你JavaScript中的this到底指向哪里

251 阅读4分钟

在编程的世界里,"this"这个词就像一个神秘的指南针,指引着函数执行的方向,决定了代码在特定上下文中如何表现自己。想象一下,如果每个函数都是一个小剧场,"this"就是那个在台上指手划脚的导演,告诉演员们(也就是函数内的代码)应该关注哪个主角——即哪个对象。今天,我们就来深入浅出地探讨JavaScript中的"this"关键字,看看它在不同场景下的指向规则,让代码美如画的小金也能轻松驾驭。

全局舞台:this与全局对象的不解之缘

首先,在JavaScript的大舞台上,有一个始终存在的主角——全局对象。在浏览器里,它叫window,而在Node.js这样的服务器端环境里,则是global。当你在全局作用域直接使用this时,它就指向这个全局对象。就像是在广阔的宇宙中,地球总是我们的家园一样自然。

console.log(this === window); // 在浏览器环境下为true

函数的多变面具:调用方式决定一切

函数是JavaScript中的表演大师,而this在函数中的指向却是个善变的角色,它的身份取决于函数是如何被召唤上台的。

默认绑定

如果一个函数孤零零地被调用,没有被任何对象所拥有,那么this就会默认指向全局对象。这就好比一个流浪艺人,在街头自弹自唱,他的观众(即函数的执行环境)默认就是整个城市(全局对象)。当一个函数独立调用时,不带任何修饰符的调用,该函数的this指向window

function sayHello() {
    console.log(this); // 在非严格模式下,指向全局对象
}
sayHello();

但在严格模式(use strict)下,这种默认绑定会被禁止,this会变成undefined,仿佛流浪艺人被禁止在公共场所表演,只能面对空气自说自话。

隐式绑定

当一个函数成为了某个对象的方法时,情况就不一样了。这时候,this就像是被领养的孩子,忠诚于它的新家庭(所属的对象)。无论何时被调用,它都指向那个对象。当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象

const person = {
    name: '小美',
    introduce: function() {
        console.log(`我是${this.name}`); // 这里的this指向person
    }
};
person.introduce(); // 输出:我是小美

隐式丢失

但事情总有例外,当函数通过一系列对象链被调用时,this可能会“忘记”它原本的家庭,转而指向链条中最接近的那个对象。当一个函数被多个对象链式调用时,this指向最近的那个对象,这也有很好记的一个方法,还记得高中英语老师上课老是念叨的就近原则吗?

const parent = { child: { grandchild: { greet: function() { console.log(this); } } } };
parent.child.grandchild.greet(); // 这里的this指向grandchild

箭头函数

箭头函数是JavaScript中的新星,它对this的态度特别坚定。不像普通函数那样善变,箭头函数直接继承了它出生时(定义时)的环境中的this值。这意味着,不管你把它丢到哪里执行,它都忠实地指向最初的主人。箭头函数中没有this这个机制,写在箭头函数中的this那也是外层非箭头函数的。

const obj = { 
    name: '小金', 
    display: () => {
        console.log(this.name); // 这里的this依然指向全局对象,不是obj
    }
};
obj.display(); // 输出可能是undefined,取决于是否是严格模式

call、apply、bind

有时候,我们需要强行改变函数执行时的this指向。这时,callapplybind这三个方法就派上用场了。它们能让你像魔法师一样,把函数的执行环境绑定到指定对象上。

function showName() {
    console.log(this.name);
}

const alice = { name: 'Alice' };
showName.call(alice); // 输出:Alice

new绑定

最后,当我们使用new关键字创建一个对象时,this会自动绑定到实例对象。这相当于给函数赋予了“造物主”的能力,每次调用都会孕育出一个新的生命,而这个生命体内流淌的血液(即this)就是它自己。

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

const bob = new Person('Bob');
console.log(bob.name); // 输出:Bob

总结

"this"虽小,却蕴含着JavaScript世界的奥秘。它既灵活又复杂,既是初学者的困惑之源,也是高手手中的利剑。掌握好"this"的指向规则,就如同拥有了在JavaScript舞台上演绎精彩剧目的秘密武器。希望这次通俗的讲解,能让小金,也让每一个热爱编程的你,对"this"有更深的理解和掌握。