疯了!js中this到底指向什么?

JavaScript/前端
290
0
0
2023-03-27

疯了!js中this到底指向什么?

一、前言

前段时间,公司让我改一个界面,我心想改个界面还不简单吗?结果呃,我低估了这颗炸弹的威力。

好吧是我太菜,总结一下,这个this的指向问题。

二、测试例子

首先说明一点。在js中,this的指向在定义函数的时候是确定不了的,只有在使用这个函数的时候才能确定this的指向。

一般来说在使用时,谁调用的这个函数,函数中的this就指向它。

2.1)普通函数

var username = "BANMOON";
let age = 18;
function showInfo(){
    console.log(username);// BANMOON
    console.log(this.username);// BANMOON

    console.log(age);// 18
    console.log(this.age);// undefined
}
showInfo();
// window.showInfo();

img

这里还涉及到varlet的区别,

  • let的作用域是在当前的代码块中,且它挂载的对象是script,而不是window
  • var的作用域是在全局,且挂载与window

由于上面两个区别,所以可以看到直接运行普通函数,其中的this是指向window的。

你可以把11行放开,这是一样的效果

2.2)对象函数

let me = {
    username: "BANMOON",
    age: 18,
    showName: function(){
        console.log(this.username);
    }
}
me.showName();// BANMOON

img

好的,和上面的呈现了不一样的效果。对象中的函数,在运行时this指向了me这个对象。

我们可以再加点料

var showName = me.showName;
showName();// undefined

img

这次又变成了undefined,我们现在再回去看看刚刚解释的那句话。

在js中,this的指向在定义函数的时候是确定不了的,只有在使用这个函数的时候才能确定this的指向。

这样,我稍微能理解点了,简单的来说就是谁调用的这个函数,函数里面的this就指向谁。

img

如果真的这么简单就好了,别急还有

2.3)构造函数

var Person = function(name, age){
    this.name = name;
    this.age = age;

    this.getName = function(){
        return this.name;
    }

    this.getFirendName = function(){
        return this.firend.getName();
    }
}

let me = new Person("BANMOON", 18)
    me.firend = new Person("阿超", 18);

console.log(`我的名字:${me.getName()}`);// BANMOON
console.log(`朋友的名字:${me.getFirendName()}`);// 阿超

img

这里没有什么好说的,同样查看谁起调的函数就好了。谁调用的那个函数,函数中的this就指向它

var User = function(username){
    this.username = username;
    this.getName = function(){
        return this.name;
    }
    return new Person("阿超", 18);
}
let user = new User("BANMOON");
console.log(user.getName());// 阿超

img

这段代码,为什么又会变成阿超呢?主要是这段函数出现了返回值,它把Person对象返回了。

所以在外部看来,user是User这个函数创建的一个对象,但实际上已经被掉包成了Person的一个对象。所以这时候,this的真正指向就是返回的那个对象。

2.4)setTimeout,apply等方法

var username = "九月";
let me = {
    username: "BANMOON",
    showName: function(){
        console.log(this.username);
    }
}
me.showName();// BANMOON

setTimeout(me.showName, 0);// undefined

img

第八行大家都知道,适应上面的逻辑,没有什么问题。可就是这个第十行,怎么就输出了九月了呢。

为什么this会指向window,请注意第10行,传入的是一个函数,me.showName没有括号。如此,这段的解释就是,在window环境下启用这个定时器,将立刻执行me.showName这个函数。

由此来看,定时器启动的函数中的this都是指向与window。我们再来看这个

var username = "九月";
let me = {
    username: "BANMOON",
    showName: function(){
        console.log(this.username);
    },
    showName2: function(){
        setTimeout(this.showName, 0)
    }
}
me.showName();// BANMOON
me.showName2();// 九月

img

如果一定要使用定时器,又不想它指向window,那该怎么办呢?

applycallbind可以解决this指向的问题

var username = "九月";
let me = {
    username: "BANMOON",
    showName: function(){
        console.log(this.username);
    },
}

let showName = me.showName;
setTimeout(function(){
    showName.apply(me);
}, 0);// BANMOON

setTimeout(function(){
    showName.call(me);
}, 0);// BANMOON

setTimeout(function(){
    let show = showName.bind(me);
    show();
}, 0);// BANMOON

img

关于他们的具体使用,本文不做详述。只是将this想指向的对象作为上面函数的参数即可。

2.5)箭头函数

var username = "阿超";
let me = {
    username: "BANMOON",
    showName: () => {
        console.log(this.username);
    },
}
me.showName();// 阿超

let aother = {
    username: "BANMOON",
    showName: function(){
        console.log(this.username);
    }
}
aother.showName();// BANMOON

img

下面那个很好理解,this指向的就是aother

那么上面的箭头函数该如何理解呢。其实是这样,箭头函数没有this,它的this来源于上一个,是继承于外面的环境。

所以me.showName()调用时,me不再生效,this将指向于window

你说箭头函数套娃?那么遇到一个往上找一个环境,直到不是箭头函数为止。

三、结语

上面的this指向,网上很有多,但我平常没有在意。用到的时候,发现储备不足。

就这样吧,我整理了一下,希望可以帮到自己。

我是半月,祝你们幸福!!!