• 技术文章 >头条

    一篇搞懂this指向,赶超70%的前端人

    青灯夜游青灯夜游2022-09-06 19:53:37转载556
    同事因为this指向的问题卡住的bugvue2的this指向问题,使用了箭头函数,导致拿不到对应的props。当我给他介绍的时候他竟然不知道,随后也刻意的看了一下前端交流群,至今最起码还有70%以上的前端程序员搞不明白,今天给大家分享一下this指向,如果啥都没学会,请给我一个大嘴巴子。

    1. 调用位置

    2. 绑定规则

      上面我们介绍了,this的指向主要跟通过什么样的形式调用有关。接下来我就给大家介绍一下调用规则,没有规矩不成方圆,大家把这几种调用规则牢记于心就行了,没有什么难的地方。

    2.1 默认绑定

       函数最常用的调用方式,调用函数的类型:独立函数调用

    function bar() {
      console.log(this) // window
    }

    2.2 隐式绑定

      用最通俗的话表示就是:对象拥有某个方法,通过这个对象访问方法且直接调用(注:箭头函数特殊,下面会讲解)

    const info = {
      fullName: 'ice',
      getName: function() {
        console.log(this.fullName)
      }
    }
    
    info.getName() // 'ice'

    隐式丢失 普通

      有些情况下会进行隐式丢失,被隐式绑定的函数会丢失绑定对象,也就是说它为变为默认绑定,默认绑定的this值,为window还是undefined取决于您当前所处的环境,是否为严格模式。

    const info = {
      fullName: 'ice',
      getName: function() {
        console.log(this.fullName)
      }
    }
    
    const fn = info.getName
    
    fn() //undefined

      这种情况下就进行了隐式丢失,丢失了绑定的对象,为什么会产生这样的问题呢?如果熟悉内存的小伙伴,就会很容易理解。

    隐式丢失 进阶
    这里大家首先要理解什么是回调函数。其实可以这样理解,就是我现在不调用它,把他通过参数的形式传入到其他地方,在别的地方调用它。

    //申明变量关键字必须为var
    var fullName = 'panpan'
    
    const info = {
      fullName: 'ice',
      getName: function() {
        console.log(this.fullName)
      }
    }
    
    function bar(fn) {
      //fn = info.getName
      fn() // panpan
    }
    
    bar(info.getName)

    2.3 显示绑定

      但是在某些场景下,this的改变都是意想不到的,实际上我们无法控制回调函数的执行方式,因此没有办法控制调用位置已得到期望的绑定即this指向。

    接下来的显示绑定就可以用来解决这一隐式丢失问题。

    2.3.1 call/apply/bind

      js中的 ”所有“函数都有一些有用的特性,这个跟它的原型链有关系,后续我会在原型介绍,通过原型链js中变相实现继承的方法,其中call/apply/bind这三个方法就是函数原型链上的方法,可以在函数中调用它们。

    2.3.2 call

    var fullName = 'panpan'
    
    const info = {
      fullName: 'ice',
      getName: function(age, height) {
        console.log(this.fullName, age, height)
      }
    }
    
    function bar(fn) {
      fn.call(info, 20, 1.88) //ice 20 1.88
    }
    
    bar(info.getName)

    2.3.3 apply

    var fullName = 'panpan'
    
    const info = {
      fullName: 'ice',
      getName: function(age, height) {
        console.log(this.fullName, age, height)
      }
    }
    
    function bar(fn) {
      fn.apply(info, [20, 1.88]) //ice 20 1.88
    }
    
    bar(info.getName)

    2.3.4 bind

    var fullName = 'panpan'
    
    const info = {
      fullName: 'ice',
      getName: function(age, height) {
        console.log(this.fullName, age, height) //ice 20 1.88
      }
    }
    
    function bar(fn) {
      let newFn = fn.bind(info, 20)
      newFn(1.88)
    }
    
    bar(info.getName)

    2.4 new绑定

      谈到new关键字,就不得不谈构造函数,也就是JS中的 "类",后续原型篇章在跟大家继续探讨这个new关键字,首先要明白以下几点,new Fn()的时候发生了什么,有利于我们理解this的指向。

    function Person(name, age) {
      this.name = name
      this.age = age
    
    }
    
    const p1 = new Person('ice', 20)
    
    console.log(p1) // {name:'ice', age:20}

    3. 绑定优先级

    3.1 隐式绑定 > 默认绑定

    function bar() {
      console.log(this) //info
    }
    
    const info = {
      bar: bar
    }
    
    info.bar()

    3.2 显示绑定 > 隐式绑定

    var fullName = 'global ice'
    const info = {
      fullName: 'ice',
      getName: function() {
        console.log(this.fullName) 
      }
    }
    
    info.getName.call(this) //global ice
    info.getName.apply(this) //global ice
    info.getName.bind(this)() //global ice

    3.3 bind(硬绑定) > apply/call

    function bar() {
      console.log(this) //123
    }
    
    const newFn = bar.bind(123)
    newFn.call(456)

    3.4 new绑定 > bind绑定

    首先我们来说一下,为什么是和bind比较,而不能对callapply比较,思考下面代码

    const info = {
      height: 1.88
    }
    
    function Person(name, age) {
      this.name = name
      this.age = age
    }
    
    const p1 = new Person.call('ice', 20)
    
    //报错: Uncaught TypeError: Person.call is not a constructor

    new绑定和bind绑定比较

    const info = {
      height: 1.88
    }
    
    function Person(name, age) {
      this.name = name
      this.age = age
    }
    
    const hasBindPerson = Person.bind(info)
    
    const p1 = new hasBindPerson('ice', 20)
    
    console.log(info) //{height: 1.88}

    3.5 总结

    new关键字 > bind > apply/call > 隐式绑定 > 默认绑定

    4. 箭头函数 (arrow function)

    首先箭头函数是ES6新增的语法

    const foo = () => {}

    4.1 箭头函数this

    var fullName = 'global ice'
    
    const info = {
      fullName: 'ice',
      getName: () => {
        console.log(this.fullName)
      }
    }
    
    info.getName() //global ice

    4.2 箭头函数的应用场景 进阶

    const info = {
      fullName: 'ice',
      getName: function() {
        let _this = this
        return {
          fullName: 'panpan',
          getObjName: function() {
            console.log(this) // obj
            console.log(_this.fullName)
          }
        }
      }
    }
    
    const obj = info.getName()
    obj.getObjName()
    const info = {
      fullName: 'ice',
      getName: function() {
        return {
          fullName: 'panpan',
          getObjName: () => {
            console.log(this.fullName)
          }
        }
      }
    }
    
    const obj = info.getName()
    obj.getObjName()

    5. 总结

    5.1 this的四种绑定规则

    5.2 this的优先级 从高到低

    6. 结语

      当一切都看起来不起作用的时候,我就会像个石匠一样去敲打石头,可能敲100次,石头没有任何反应,但是101次,石头可能就会裂为两半 我知道并不是第101次起了作用,而是前面积累所致。

      大家有疑惑可以在评论区留言 第一时间为大家解答。

    (学习视频分享:web前端开发

    php入门到就业线上直播课:查看学习

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    专题推荐:javascript this
    上一篇:【整理分享】50+ 个实用VSCode插件,快来收藏使用! 下一篇:2022中秋节赏月特效代码+网站素材【免费下载】
    VIP课程(WEB全栈开发)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• 聊聊vue2.x中this的指向问题,它为什么指向vue实例?• 浅析Vue中的Vue.set和this.$set,看看使用场景!• php中$this->方法是什么• 你能搞懂JS的this指向问题吗?看看这篇文章• 详细解析Java的this和super关键字• 什么是this?深入解析JavaScript中的this
    1/1

    PHP中文网