Javascript中的this指向问题总结
记住两点
- this的指向永远是一个对象
- this的指向完全取决于函数的调用位置
总的来说就是谁调用就指向谁
普通函数中的this指向
首先普通函数的this分两种情况,严格模式和非严格模式
//严格模式
function test(){
console.log(this)
}
test() //undefined
window.test()//window
//非严格模式
function test(){
console.log(this)
}
test() //window
window.test()//window
对象中的this指向
原则:对象中谁调用就指向谁
const Person={
name:'张三',
skill:function(){
name:'李四',
console.log(this.name)
},
person2:{
name:'王五',
skill:function(){
name:'老六',
console.log(this.name)
}
}
}
Person.skill()//张三
Person.person2.skill()//王五
- 对象中谁调用了函数this就指向谁
- 多层嵌套对象,内部方法的this就指向离被调函数最近的对象
构造函数中的this指向
构造函数中的this指向创建的实例对象
function Person(name,sex,age){
this.name=name;
this.sex=sex;
this.age=age;
}
var messgae=new Person('张三','男',18);
console.log(message.name);//张三
console.log(message.sex);//男
console.log(message.age);//18
箭头函数中的this指向
箭头函数中没有this,它会绑定最近的非箭头函数作用域的this。首先从它的父级作用域找,如果父级作用域还是箭头函数,就再往上找,直到找到this指向
var test=()=>{console.log(this)}
var obj={test:test}
//等价于
//obj={
// test:()=>{
// console.log(this)
// }
//}
test()//window
obj.test()//winow
第一个直接调用test相当于window.test()因此this指向window
第二个test是箭头函数往上一步找作用域找到了obj,obj是对象不是箭头函数则this绑定到了obj上,window调用obj,所以this的指向就指向了window相当于window.obj.test()
特殊函数的this指向(定时器)
const test={
count:function(delay=1000){
setTimeout(function(){
console.log(this)
},delay)
}
}
test.count()//window
当定时器的回调函数用匿名函数的时候this指向window
使用箭头函数可以保全this的作用域
const tahoe={
hills:['Rose','Tallac','Silver'],
print:function(delay=1000){
setTimeout(()=>{
console.log(this.hills.join(","));
},delay);
}
}
tahoe.print();//Rose,Tallac,Silver
//报错一:
const tahoe={
hills:['Rose','Tallac','Silver'],
print:function(delay=1000){
setTimeout(function(){
console.log(this.hills.join(","));
},delay);
}
}
tahoe.print();//Uncaught TypeError:cannot read property 'join' of undefined
//报错二:
const tahoe={
hills:['Rose','Tallac','Silver'],
print:(delay = 1000)=>{
setTimeout(()=>{
console.log(this.hills.join(","));
},delay);
}
}
tahoe.print();//Uncaught TypeError:cannot read property 'join' of undefined
使用了箭头函数this的指向setTimeout的上一层作用域function,然后是对象tahoe调用了print方法,所以这里的this指向tahoe对象,因此对象上有hills这个数组属性。要是setTimeout回调函数使用匿名函数,这个的代码就会报错,因为window上没有hills这个数组。要是print方法使用的是箭头函数又会报错,因为继续往上找一层作用域,然后this的指向重新指向window,window上没有hills这个数组。
改变this指向(apply、call、bind)
apply和call
- apply('你想指定的上下文',[存放函数传入的参数(数组形式)])
- call('你想指定的上下文',传入函数的第一个参数,传入函数的第二个参数,...)
var name='张三'
var person={
name:'李四'
}
function showName(info1,info2){
console.log(this.name,info1,info2)
}
showName('hello',18)//张三 hello 18
showName.apply(person,['hello',18])//李四 hello 18
showName.call(person,'hello',18)//李四 hello 18
bind
bind和call的语法一样,只是call会立即执行函数,而bind会返回一个新的函数不会立即执行
var name='张三'
var person={
name:'李四'
}
function showName(info1,info2){
console.log(this.name,info1,info2)
}
showName('hello',18)//张三 hello 18
var newShowName=showName.bind(person)//并不会执行,而是返回了一个新函数newShowName
newShowName('hello',18)//李四 hello 18
//var newShowName=showName.bind(person,'haha',36)//并不会执行,而是返回了一个新函数newShowName
//newShowName('hello',18)//李四 haha 36
//函数新传入的参数会拼接在后面,这里一共四个参数传入('haha',36,'hello',18),所以只输出了前两个参数