在JavaScript语言中,this是一个很神奇的存在,this指向是一个让初学者感到困惑和纠结的问题。
有console.log函数帮助我们在学习过程中总结,this指向还是有一般规律可循的。
1、在函数中直接使用时(不使用任何修饰符,比如call、apply、bind、new等),函数中的this默认绑定到全局,就是指向window。需要注意的是,当使用严格模式时,不能绑定到全局,程序会抛出错误。
function func(){ console.log(this); }
func();
a=function(){ console.log(this); }
a();
var b={ x:this }
console.log(b.x);
输出结果:
2、在函数中的this指向不是在函数定义时确定的,需要在运行时确定,具体说就是this指向函数运行时的调用者。回调函数中的this一般指向调用者。
这个好理解,在网页中我们经常使用回调函数,比如:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<button id=demo>点击</button>
</body>
<script>
demo.addEventListener('click',function(){
console.log(self);//this指向window
console.log(this);//this指向button
})
// document.getElementById("demo").addEventListener('click',function(){
// console.log(self);//this指向window
// console.log(this);//this指向button
// })
</script>
</html>
下面的例子却有不一样的显示结果。
function info(student){
console.log(this);
return '姓名:'+student.sName+',年龄:'+student.age+',性别:'+student.gender;
}
var student={
sName:'无',
age:0,
gender:'无'
}
function sayHello(student,info){
return info(student);
}
var stuA=new Object();
stuA.prototype=student;
stuA.sName='小王';
stuA.age=11;
stuA.gender='男';
console.log(sayHello(stuA,info));
var stuB=new Object();
stuB.prototype=student;
stuB.sName='小宋';
stuB.age=9;
stuB.gender='女';
sayHello(stuB,function(stuB){
console.log(this);
console.log('姓名:'+stuB.sName+',年龄:'+stuB.age+',性别:'+stuB.gender);
});
输出结果:
回调函数里的this指向的是window。这个是可以理解的,因为回调函数info是由sayHello调用执行的,而sayHello中的this指向的就是window。
在这个例子当中如果要使用this来改写,就可以使用call方法。
function info(){
console.log(this);
return '姓名:'+this.sName+',年龄:'+this.age+',性别:'+this.gender;
}
var student={
sName:'无',
age:0,
gender:'无'
}
function sayHello(student,info){
return info.call(student);//绑定this到形参student所指的对象
}
var stuA=new Object();
stuA.prototype=student;
stuA.sName='小王';
stuA.age=11;
stuA.gender='男';
console.log(sayHello(stuA,info));
var stuB=new Object();
stuB.prototype=student;
stuB.sName='小宋';
stuB.age=9;
stuB.gender='女';
sayHello(stuB,function(stuB){
console.log(this);
console.log('姓名:'+this.sName+',年龄:'+this.age+',性别:'+this.gender);
});
使用call方法改变了回调函数中的this指向。
3、函数中的方法调用,如果是绑定到属性,则是指向该属性的函数。
function Info(Name,age,gender){
console.log(this);
return '姓名:'+Name+' 年龄:'+age+' 性别:'+gender;
}
console.log(Info('11','22','33'));
var student={
that:this,
sName:'小红',
age:11,
gender:'女',
sayHelloA:Info('100','200','300'),
sayHelloB:Info,
sayHelloC:Info,
sayHelloD:function(){ return Info.call(this,this.sName,this.age,this.gender); },
sayHelloE:function(){ return '★姓名:'+this.sName+' 年龄:'+this.age+' 性别:'+this.gender; }
}
console.log('---student中的this---');
console.log(student.that);
console.log('---student.sayHelloA---');
console.log(student.sayHelloA);
console.log('---student.sayHelloB---');
console.log(student.sayHelloB(student.sName,student.age,student.gender));
console.log('---student.sayHelloC---');
console.log(student.sayHelloC.call(student,student.sName,student.age,student.gender));
console.log('---student.sayHelloD----');
console.log(student.sayHelloD());
console.log('---student.sayHelloE----');
console.log(student.sayHelloE());
输出结果:
4、箭头函数,逐渐向外层父元素来查找this,箭头函数一般不重新绑定this指向。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<button id=demo>点击</button>
</body>
<script>
demo.addEventListener('click',function(){
console.log(self);//this指向window
console.log(this);//this指向button
setTimeout.call(window,()=>{
console.log('----------------');
console.log(this);
},1000);
})
// document.getElementById("demo").addEventListener('click',function(){
// console.log(self);//this指向window
// console.log(this);//this指向button
// })
</script>
</html>
输出结果:
即使在settimeout函数中绑定了window,this指向输出的还是button。
作为对比,如果换成普通函数,this的指向就改变了。
demo.addEventListener('click',function(){
console.log(self);//this指向window
console.log(this);//this指向button
setTimeout.call(window,function(){
console.log('----------------');
console.log(this);//指向window
},1000);
})
输出结果: