疯了!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();
这里还涉及到var
和let
的区别,
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
好的,和上面的呈现了不一样的效果。对象中的函数,在运行时this
指向了me
这个对象。
我们可以再加点料
var showName = me.showName;
showName();// undefined
这次又变成了undefined
,我们现在再回去看看刚刚解释的那句话。
在js中,this
的指向在定义函数的时候是确定不了的,只有在使用这个函数的时候才能确定this
的指向。
这样,我稍微能理解点了,简单的来说就是谁调用的这个函数,函数里面的this
就指向谁。
如果真的这么简单就好了,别急还有
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()}`);// 阿超
这里没有什么好说的,同样查看谁起调的函数就好了。谁调用的那个函数,函数中的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());// 阿超
这段代码,为什么又会变成阿超呢?主要是这段函数出现了返回值,它把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
第八行大家都知道,适应上面的逻辑,没有什么问题。可就是这个第十行,怎么就输出了九月了呢。
为什么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();// 九月
如果一定要使用定时器,又不想它指向window
,那该怎么办呢?
apply
,call
,bind
可以解决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
关于他们的具体使用,本文不做详述。只是将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
下面那个很好理解,this
指向的就是aother
。
那么上面的箭头函数该如何理解呢。其实是这样,箭头函数没有this
,它的this
来源于上一个,是继承于外面的环境。
所以me.showName()
调用时,me
不再生效,this
将指向于window
你说箭头函数套娃?那么遇到一个往上找一个环境,直到不是箭头函数为止。
三、结语
上面的this
指向,网上很有多,但我平常没有在意。用到的时候,发现储备不足。
就这样吧,我整理了一下,希望可以帮到自己。
我是半月,祝你们幸福!!!