this 的指向问题一直是一个难题,我看过很多有关this的文章,当时都大致都懂了,但是过一段时间后还是忘记。是因为记得不牢固的原因。
想要牢固的记住this指向问题,就自己来总结一篇“属于你自己的this指向问题”。
先来例子:
let myObject = {
name: "phoebe",
age: 22,
aboutMe: function(){
return "My name is "+this.name+", I am "+this.age + " years old"
}
}
console.log(myObject.aboutMe());
此时,打印出来的是: My name is phoebe, I am 22 years old
let myObject2 = {
name: "phoebe",
age: 22,
aboutMe: function(){
return "My name is "+this.name+", I am "+this.age + " years old"
},
friends: {
name: "fanfan",
age: 24,
aboutMe: function(){
return "My friend's name is "+this.name+", he is "+this.age + " years old"
}
}
console.log(myObject2.aboutMe());
console.log(
myObject2.friends.aboutMe()) // ;
此时,打印出来的是: My name is phoebe, I am 22 years old
My friend's name is fanfan, he is 24 years old
这时我们可以总结: this关键字总是隐式的去引用离他最近的包含对象
或者是说永远指向最后调用他的那个对象
myObject2.aboutMe() // this指向的是myObject2
myObject2.friends.aboutMe()) // this指向的是myObject2里的friends对象
再看一个例子:
let myObject3 = {
firstName: "Harry",
age: 20,
aboutMe: function(){
setTimeout(function(){
console.log(this.firstName + " is " + this.age + " years old")
},5000)
}
}
myObject3.aboutMe();
此时,打印的结果便是undefined is undefined years old.
setTimeout函数是一个异步函数,他会在宏任务中的同步函数调用完后,再去调用。5秒后再去执行时,this所在的环境就是全局环境。指向的也是全局变量(window),而在全局环境中,fristname和age属性都是未定义的。所以会报undefined。
此时,要想正常运行我们需要怎样做呢?
那就是把this再重新指回来,重新指向myObject3这个对象。
方法:
1.箭头函数(最方便的)
2.call
3.apply
4.bind
箭头函数的使用,推荐去看阮大神的书籍。
call方法的使用:
let user1 = {
name: "Tony",
sayHi: function(){
return this.name + " says Hi"
}
}
let user2 = {
name: "Martha",
sayHi: function(){
return this.name + " says Hi"
}
}
console.log(user1.sayHi()); //Tony says Hi
console.log(user2.sayHi()); //Martha says Hi
两个对象都有sayHi方法,那我们可不可以减少代码只保留一个sayHi方法。
let user1 = {
name: "Tony",
sayHi: function(){
return this.name + " says Hi"
}
}
let user2 = {
name: "Martha"
}
console.log(user1.sayHi()); //Tony says Hi
console.log(user1.sayHi.call(user2)); //Martha says Hi
可以达到相同的效果,如何我们想增加一些参数呢?
let user1 = {
name: "Tony",
greet: function(msg, friend){
return this.name + " says " +msg+ " to "+friend
}
}
let user2 = {
name: "Martha"
}
console.log(user1.greet("Hi", "James"));
//Tony says Hi to James
console.log(user1.greet.call(user2, "Hello", "Habeeb"));
//Martha says Hello to Habeeb
call方法可以接收多个参数
apply方法的使用:
apply方法和 call方法是很像的,唯一不同的是 apply方法只需要一个参数,(如果需要多个参数时,就要用数组了) console.log(user1.greet.apply(user2, ["Hello", "Habeeb"]));
bind方法的使用:
返回一个他所调用的函数,但不会立即去执行他。let myObject4 = {
firstName: "Michael",
age: 20,
aboutMe: function(){
setTimeout(function(){
console.log(this.firstName + " is " + this.age + " years old")
}.bind(myObject4),5000)
}
}
myObject4.aboutMe(); //Michael is 20 years old