前言
网上关于箭头函数 this 指向的问题的讲解实在太多了,理解也很多,貌似真的很难找到最正确的标准。
看了大量文章之后,你可能还是很迷糊,我觉得问题可能在于,他们给你们解释之前已经默认了你掌握了基础,所以忽略了一些最最基础的定义解释,可能跟你说了 this 的指向问题,但是没有跟你说明 this 出现的前提。
我觉得,概念都是人创造出来的,只要能合理的解释结果,就是正确的理解,接下来我教会你们,我的理解方法。
this定义
首先,我们要知道一些定义,js
拥有函数和对象,我们都很熟悉,对象中也可以声明函数,当一个对象中拥有函数时,我们将该函数成为该对象的方法,函数具有函数作用域,所以方法也是函数,也有自己的方法作用域。
然后我们说结论:
方法中可以使用this
,this
指向该方法作用域所在的对象。
而我们html
的js
中,对象分为全局 window 对象和我们手动声明的对象。
所以一般有三种情况:
- 在
window
对象下直接调用this
,得到window
对象。 - 在
window
下创建的普通函数,默认下也得到window
对象,方便理解,我们可以把它想象成window
对象的方法。(如果是严格模式,则是undefined,毕竟,该函数并非真正的方法) - 在手动创建的对象中的普通函数,得到对应的对象。
文字看不明白就直接看例子:
// 情况1
console.log(this) // Window{}
// 情况2
function fun() {
console.log(this)
}
fun() // Window{}
// 情况3
const A = {
// 方法作用域对应的对象是 A 对象
showThis: function () {
console.log(this)
}
}
A.showThis() // A{}
箭头函数中的this
首先我们要知道:箭头函数没有自己的作用域,它的作用域就是上级方法的作用域,所以箭头函数也没有自己的 this,它的 this 就是上级方法作用域的 this。
所以,当对象中是箭头函数时,它的上级已经没有方法作用域了,它的上级就是全局window作用域,所以它内部的 this 指向 window。
const A = {
showThis: () => {
console.log(this)
}
}
A.showThis() // Window{}
所以只要我们套一个普通函数作用域给它就会这样(这里其实还涉及高阶函数下箭头函数指向未改变的问题,我们会在下文提到):
const A = {
showThis: function () {
return () => {
console.log(this)
}
}
}
A.showThis()() // A{}
this可以被改变
第一种改变方式
我们可以用 apply、call 等函数改变this指向。
不明白 apply、call 用法可以先移步:js apply、call、bind一篇掌握。
简单例子:
const A = {
showThis: function () {
console.log(this)
}
}
const B = {}
// 等于使用 B 调用了这个函数,所以可以看作该方法作用域的所在对象是 B
A.showThis.apply(B) // B{}
第二种改变方式
当我们创建了一个变量,并赋值一个某个对象的方法,this可能会改变,其实这不能算作一种真正的改变,只能说是调用的时候我们看到的结果改变了,我将这种方法称为重新声明。
const A = {
showThis: function () {
console.log(this)
}
}
const B = {
name: 'B'
}
// 等于将所在对象改变为 Window 对象
const test = A.showThis
test() // Window{}
// 等于将所在对象改变为 B 对象
B.showThis = A.showThis
B.showThis() // B{}
箭头函数中的 this 不会被改变
上文中我们提到过,箭头函数没有自己的 this,所以我们没办法改变它内部 this 的指向,两种方法都没有用。
apply方法不行:
const A = {
showThis: () => {
console.log(this)
}
}
const B = {name: 'B'}
A.showThis() // Window{}
A.showThis.apply(B) // Window{},没变
重新声明法也不行:
const A = {
showThis: () => {
console.log(this)
}
}
const B = {
name: 'B'
}
A.showThis() // Window{}
B.showThis = A.showThis
B.showThis() // Window{},没变
高阶函数下的情况
如果你觉得上述的内容你已经完全理解了,可以跳过该节,该节容易引起混乱。
其实原理是一样的,就是可能高阶函数看起来比较复杂,如果你能掌握前面的知识点,一步步去理解就ok了。
高阶函数下一般例题就是普通函数包裹普通函数,或者普通函数包裹箭头函数:
const A = {
name: 'A',
showThis: function () {
return function () {
console.log(this)
}
},
showThis2: function () {
return () => {
console.log(this)
}
}
}
A.showThis()() // Window
A.showThis2()() // A{}
如何理解呢?
我们看到这种高阶函数,可以理解为运行是分为了两步,重新声明了函数再运行,所以是尝试改变了一次 this 指向。
const A = {
name: 'A',
showThis: function () {
return function () {
console.log(this)
}
},
showThis2: function () {
return () => {
console.log(this)
}
}
}
// 由于A.showThis()高阶函数返回了一个普通函数,重新声明,所以this指向被改变了,改变到Window
const test = A.showThis()
test() // Window
// 由于A.showThis2()高阶函数返回了一个箭头函数,重新声明,this指向仍未改变
const test2 = A.showThis2()
test2() // A{}
我们继续,如果使用 apply 改变指向,结果同样可以根据箭头函数不会被改变this指向理解:
const A = {
name: 'A',
showThis: function () {
return function () {
console.log(this)
}
},
showThis2: function () {
return () => {
console.log(this)
}
}
}
const B = {
name: 'B'
}
// 由于A.showThis()高阶函数返回了一个普通函数,apply方法,所以this指向被改变了,改变到B
A.showThis().apply(B) // B{}
// 由于A.showThis2()高阶函数返回了一个箭头函数,apply方法,this指向未改变
A.showThis2().apply(B) // A{}
虽然 showThis2 中返回的箭头函数 this 指向不会被改变,但是 showThis2 自己是普通函数,它的 this 指向是可以改变的,且它的 this 指向就是它内部的箭头函数的 this 指向,也一同改变了:
const A = {
name: 'A',
showThis: function () {
return function () {
console.log(this)
}
},
showThis2: function () {
return () => {
console.log(this)
}
}
}
const B = {
name: 'B'
}
A.showThis2.apply(B)() // B{}
// 等同于
// A.showThis2.apply(B)等于改变了showThis2这个普通函数的this指向到B
// 又由于A.showThis2.apply(B)返回的是箭头函数,重新声明,也不会改变指向
const test = A.showThis2.apply(B)
test() // B{}
测试例题
最终例题,可以尝试理解一下,不理解重新去阅读上文:
const A = {
name: 'A',
showThis: function () {
console.log(this)
},
showThis2: () => {
console.log(this)
},
showThis3: function () {
return function () {
console.log(this)
}
},
showThis4: function () {
return () => {
console.log(this)
}
}
}
const B = {
name: 'B'
}
A.showThis() // A{}
A.showThis.apply(B) //B{}
A.showThis2() // Window{}
A.showThis2.apply(B) // Window{}
A.showThis3()() // Window{}
// 等同于
const test = A.showThis3() // 普通函数改变指向
test() // Window{}
A.showThis3().apply(B) // B{}
A.showThis3.apply(B)() // Window{}
// 等同于
const test2 = A.showThis3.apply(B) // apply方法,先改变到B,重新声明,再改变到Window
test2() // Window{}
A.showThis4()() // A{}
// 等同于
const test3 = A.showThis4() // 箭头函数不改变指向
test3() // A{}
A.showThis4().apply(B) // A{}
A.showThis4.apply(B)() // B{}
// 等同于
const test4 = A.showThis4.apply(B) // apply改变了指向showThis4指向B,箭头函数重新声明不改变指向
test4() // B{}
尾言
掌握这个,需要花一定时间理解,并能够自己分析出结果。
如果觉得文章对你有帮助的话,欢迎点赞收藏哦,有什么错误或者意见建议也可以留言,感谢~