js this指向详解

前言

网上关于箭头函数 this 指向的问题的讲解实在太多了,理解也很多,貌似真的很难找到最正确的标准。

看了大量文章之后,你可能还是很迷糊,我觉得问题可能在于,他们给你们解释之前已经默认了你掌握了基础,所以忽略了一些最最基础的定义解释,可能跟你说了 this 的指向问题,但是没有跟你说明 this 出现的前提

我觉得,概念都是人创造出来的,只要能合理的解释结果,就是正确的理解,接下来我教会你们,我的理解方法。

this定义

首先,我们要知道一些定义,js拥有函数对象,我们都很熟悉,对象中也可以声明函数,当一个对象中拥有函数时,我们将该函数成为该对象的方法,函数具有函数作用域,所以方法也是函数,也有自己的方法作用域

然后我们说结论:

方法中可以使用thisthis指向该方法作用域所在的对象

而我们htmljs中,对象分为全局 window 对象和我们手动声明的对象

所以一般有三种情况:

  1. window对象下直接调用this,得到window对象。
  2. window下创建的普通函数,默认下也得到window对象,方便理解,我们可以把它想象成window对象的方法。(如果是严格模式,则是undefined,毕竟,该函数并非真正的方法
  3. 在手动创建的对象中的普通函数,得到对应的对象。

文字看不明白就直接看例子:

    // 情况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{}
    

尾言

掌握这个,需要花一定时间理解,并能够自己分析出结果。

如果觉得文章对你有帮助的话,欢迎点赞收藏哦,有什么错误或者意见建议也可以留言,感谢~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在下月亮有何贵干

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值