js中的this是一个老生常谈的话题。这篇文章可能是对于this来讲最全面的解读了,仔细看。
1.首先,要明白js中对象的概念,我们说js的对象大致分为dom对象,bom对象,也就是说,html页面叫对象,浏览器算对象,js中自己建立的对象也叫对象。
实际上,我们在日常编程的过程中很可能没有建立对象,可能写代码的时候谢了n多个变量,写了n多个方法,程序也能正常运行。
于是你会说,我也没用对象啊?实际上,你写的所有的变量,方法都保存在window对象里。window是一个浏览器的全局对象,例如
var a=1;
console.log(a);//1
console.log(window.a);//1
执行结果都是1,事实上这个变量a被当做是window对象的一个属性了而已。再如:
function fun(){
console.log(1);
}
fun();//1
window.fun();//1
你写的所有的方法,函数,实际上就是window对象内部的一个函数而已。
那么问题来了,讲了这么半天,跟this有什么关系呢?this在英文中有指代的意味,代指“这个”。那我们把上面两段代码用this代指一下。
var a=1;
console.log(a);//1
console.log(this.a);//1
function fun(){
console.log(1);
}
fun();//1
this.fun();//1
可以看到,这段代码中我不再使用window对象,而是直接使用的this,也可以打出4个1。同样的效果,于是乎我们就知道了,当你的变量和函数外部没有任何对象时,也就是常规情况下你写的变量和方法
都暴露给window对象的时候,this代指的就是window。当然这是针对于原生js而言,像vue和微信小程序这样的mvvm框架中,这种情况下this指向undefined。
2. 现在场景换了,我们自己写了个对象,里面有一定的方法和变量,例如:
var student={
name:"张三",
age:24,
sayhello:function(){
console.log('我是'+name,'今年'+age+'岁');
}
}
student.sayhello();
执行这段代码,结果是undefined,为啥,为啥undefined,因为fun()函数并不认识name,age,都是一个对象内部的变量,方法,怎么还就不能访问了呢?是的就是不能访问。
那怎么能访问呢?很简单,加上this,像这样写:
var student={
name:'张三',
age:24,
sayhello:function(){
console.log('我是'+this.name,'今年'+this.age+'岁');
console.log(this);
}
}
student.sayhello();
没问题,能够执行,那我们就要想一个问题了,这里的this代表的是谁?我们不妨把他打印出来看看
打印出了一个对象,就是student这个对象。那么我们可以总结,当在对象内部使用this的时候,this指向对象本身。这个例子里面我们是自己建立的对象,实际上如果是别的对象道理也相同比如现在
是一个dom对象
<html>
<head>
</head>
<body >
<div style="width:200px;height:200px" id="bd"></div>
<button onclick="press()">按我div变红</button>
<script type="text/javascript">
function press()
{
document.getElementById('bd').style.backgroundColor='red';
console.log(this);//window
}
</script>
</body>
</html>
3.在上面这段代码中,js里面只有一个函数,没有新建的对象,调用这个函数的对象是button标签,隶属于window对象因此打印结果肯定是window;
4.关于回调函数中this的使用,回调函数中的this是一个特例,他不满足与前面我们提到过的理论,假设现在有这样一个场景:
var student={
name:'张三',
age:24,
$.ajax({
type:'GET',
url:url,
success:function(res){
this.name=res.a;
this.age=res.b;
console.log(this);
})
}
}
还是一个对象里边,有几个属性,然后有异步请求,有一个回调函数,现在我想让回调函数里带回来的值a,b赋给对象里已经建立好的属性name,age,并且呢我还想查看一下这时候的this指向的是谁
按照之前的理论,毫无疑问这件事能够做成,name和age都能够获得值,this应该指的是当前对象,但是实践证明,不但name和age得不到应有的值
this指向的也不是当前对象。打印this你会发现结果是undefinded,这也是vue框架,包括微信小程序中经常遇到的问题。
那么首先来说原因,为什么this指向的就不是当前对象了呢。这还得从js的事件循环机制说起,异步函数通常是在方法栈中等待同步任务执行完成之后才执行的,因此当他执行结束后堆栈中的内容
又会重新刷新,这时候回调函数已经和他所在的对象分离了,所以它并不知道该指向哪,于是乎就是undefined。
那么怎么解决这个问题呢。有两种办法,第一种是在回调函数执行之前拷贝一份对象this,等结束后让它继续用这个this,像这样写:
var student={
var _this=this;
name:'张三',
age:24,
$.ajax({
type:'GET',
url:url,
success:function(res){
_this.name=res.a;
_this.age=res.b;
console.log(_this);
})
}
}
这样的话回调函数就能找到自己所在的对象,从而完成数据的传递。
第二种办法就是使用ES6的箭头函数。箭头函数不同于普通的函数,他的this指向它定义时所处在的对象,而不是执行时所在的对象
这样一来就不管你异步函数执行时,执行完成之后,只关心异步函数定义时所在的位置,这样就可以自然的使用this了,代码如下:
var student={
name:'张三',
age:24,
$.ajax({
type:'GET',
url:url,
success(res)=>{
this.name=res.a;//光明正大的使用this,这时的this就指向student本身
this.age=res.b;
console.log(this);
})
}
}
实际上对于普通的回调函数无法获取this指向的问题是js的一个设计缺陷,随着ES6的诸多改进,变量以及函数的作用域划分的越来越清楚,自然也就不存在这种问题了
所以还是推荐大家尽量多使用ES6的语法去书写代码。