普通函数this指向
函数的this指向遵循一个基本原则:谁调用的函数,函数的this就指向谁,否则指向全局
示例
var name = 'window'
let obj = {
name: 'object',
sayHi: function () {
console.log(this.name)
},
sayFoo: function () {
return function () {
console.log(this.name)
}
}
}
// 问题1
obj.sayHi() // object
// 问题2
obj.sayFoo()() // window
-
问题1解析,因为sayHi方法是obj调用的,所以sayHi函数的this就指向了obj,所以this.name相当于obj.name,因此打印object
-
问题2解析:首先sayFoo方法是obj调用的,所以sayFoo函数的this指向obj,但由于sayFoo()方法返回了一个新的匿名函数fn,所以obj.sayFoo()(),相当于fn(),而该匿名函数fn并没有指定的调用者,所以fn函数内部的this指向window,所以打印window
箭头函数this指向
首先我们要知道,箭头函数本身是没有 this,箭头函数 this 是定义箭头函数时父级作用域的 this,也就是说使用箭头函数时,箭头函数内部的 this,我们只需要看定义该箭头函数时,该箭头函数父级的 this 即可
示例
var name = 'window'
let obj1 = {
name: 'obj',
sayHi: () => {
console.log(this.name)
},
sayFoo: () => {
return () => {
console.log(this.name)
}
}
}
// 问题1
obj1.sayHi() // window
// 问题2
obj1.sayFoo()() // window
- 问题1解析:我们可能会困惑,为什么打印的时window?我们上面说过了,箭头函数本身是没有this的,所以我们并不关心谁调用的它,关键是看定义该箭头函数时,其父级作用域的this。上面的例子,定义箭头函数时,其父级作用域是全局,所以该箭头函数this指向的是window
- 问题2解析:首先sayFoo函数返回一个匿名的箭头函数,该匿名箭头函数this指向的就是sayFoo函数的this,而sayFoo也是一个箭头函数,所以它的this指向window,所以返回的匿名的箭头函数this指向window
普通函数与箭头函数组合使用
示例
var name = 'window'
let obj2 = {
name: 'obj',
sayHi: () => {
return function () {
console.log(this.name)
}
},
sayFoo: function () {
return () => {
console.log(this.name)
}
}
}
// 问题1
obj2.sayHi()() // window
// 问题2
obj2.sayFoo()() // obj
- 问题1解析:sayHi函数返回一个新的匿名函数,所以主要看是谁调用的这个函数,因为没有具体的调用者,所以this指向全局
- 问题2解析:sayFoo函数返回一个新的匿名箭头函数,所以主要看定义该箭头函数时其父级的this,其父级的this指向的是该函数的调用者,所以this指向obj
call/apply/bind
call、apply、bind可以改变函数内部的this指向,但由于箭头函数自身没有this,所以call、apply、bind对箭头函数是不起作用的
示例
var name = 'window'
let obj3 = {
name: 'obj',
sayHi: () => {
console.log(this.name)
},
sayFoo: function () {
console.log(this.name)
}
}
let obj4 = {
name: 'other'
}
obj3.sayHi.call(obj4) // window,call对箭头函数不起作用
obj3.sayFoo.call(obj4) // other,call可以改变函数内部的this到指定变量