# 前言

  JavaScript 语言之中,一切皆对象,运行环境也是对象。函数都是在某个对象之中运行,this 就是函数运行时所在的对象(环境)。

  本文将介绍 this 关键字的各种用法,以及 this 关键字的指向。

当我们在编写代码时,无法获取某些方法和属性时,我们可以尝试使用 this 关键字来获取。

# 一、this 关键字

  -this不管在什么场合,它总是返回一个对象。

# 1、this 认知

  在 JavaScript 中,this 是一个特殊关键字,它代表当前执行代码的上下文,即当前执行的函数或方法所属的对象

this.property

  值得注意的是,this 关键字并不是一定要使用的。

this 关键字在函数中是隐式使用的,但是在一些特殊的情况下,this 关键字会显式使用。

      通常情况下,this有如下几个应用场景(使用角度):

        除此之外,还有一些地方会涉及到 this (相关角度):

        # 2、指向汇总 🎯

          this 的指向是当我们调用函数的时候确定的,调用方式的不同决定了 this 的指向不同。

        调用方式 this 指向
        对象方法 该方法所属对象
        箭头函数(👀) 外层作用域的 this
        定时器函数 window
        立即执行函数(IIFE) window
        回调函数(👀) window
        构造函数 生成的对象实例
        事件绑定方法 绑定事件对象

          为了解决全局作用域函数(立即执行函数、回调函数、定时器函数)的 this 指向问题,总结有如下几种方案:

        // 方案一:使用that
        btn.onclick = function () {
          this.disabled = true
          var that = this
        
          setTimeout(function () {
            that.disabled = false
          }, 3000)
        }
        
        // 方案二:使用bind
        btn.onclick = function () {
          this.disabled = true
        
          setTimeout(
            function () {
              this.disabled = false
            }.bind(this),
            3000
          )
        }
        
        // 方案三:使用箭头函数
        btn.onclick = function () {
          this.disabled = true
        
          setTimeout(() => {
            this.disabled = false
          }, 3000)
        }
        

        # 3、回调函数

          下面我们可以自己模拟写一个 filter 函数

        数据示例
        // 示例数据
        let cardList = [
          {
            id: 1,
            category: 'werewolf',
            name: '小狼人'
          },
          {
            id: 2,
            category: 'werewolf',
            name: '小狼人'
          },
          {
            id: 3,
            category: 'hunter',
            name: '猎人'
          },
          {
            id: 4,
            category: 'poor',
            name: '平民'
          },
          {
            id: 5,
            category: 'witch',
            name: '女巫'
          },
          {
            id: 6,
            category: 'prophet',
            name: '预言家'
          },
          {
            id: 7,
            category: 'poor',
            name: '平民'
          },
          {
            id: 8,
            category: 'werewolf',
            name: '黑狼王'
          },
          {
            id: 9,
            category: 'poor',
            name: '平民'
          }
        ]
        
        // 目标数据
        let newcardList = [
          {
            id: 1,
            category: 'werewolf',
            name: '小狼人'
          },
          {
            id: 2,
            category: 'werewolf',
            name: '小狼人'
          },
          {
            id: 8,
            category: 'werewolf',
            name: '黑狼王'
          }
        ]
        

        forEach(callbackFn, thisArg)

        // 1、使用原生filter
        let newcardList = cardList.filter((item) => item.category == 'werewolf')
        
        // 2、使用自己封装filter
        Array.prototype.myFilter = function (cb) {
          // console.log(this)
          // console.log(cb(this[1]))
        
          let arr = []
          for (let index = 0; index < this.length; index++) {
            // filter方法:给定条件,返回数组
            if (cb(this[index])) {
              arr.push(this[index])
            }
          }
          return arr
        }
        let newcardList = cardList.myFilter((item) => item.category == 'werewolf')
        

        # 4、箭头函数

          与普通函数相比:

        • 箭头函数没有 this 对象,它的 this 继承自外层作用域的 this。
        • 箭头函数没有 arguments 对象,取而代之用 rest 参数… 解决

        箭头函数都是匿名函数,不能用于构造函数、类、对象字面量、模块等。

        const obj = {
          name: 'lencamo',
          sayName: function () {
            console.log(this.name) // 'lencamo'
            console.log(arguments) // ["hello", "world"]
          },
          sayName2: (...args) => {
            console.log(this.name) // 'JS Bin Output'
            console.log(args) // ["hello", "world"]
          }
        }
        
        obj.sayName('hello', 'world')
        

        # 二、上下文函数

          上下文函数是指函数的运行环境,它决定了函数体内的 this 指向。

        xxx(thisArg, ……)
        

        # 1、call 方法

        • 立即执行
        • 参数列表
        let person = {
          name: '任先生'
        }
        
        function sayName(...args) {
          console.log(this.name)
          console.log(args) // ["hello", "world"]
        }
        
        sayName.call(person, 'hello', 'world')
        

        # 2、apply 方法

        • 立即执行
        • 参数数组
        let person = {
          name: '任先生'
        }
        
        function sayName(...args) {
          console.log(this.name)
          console.log(args) // ["hello", "world"]
        }
        
        sayName.apply(person, ['hello', 'world'])
        

        # 3、bind 方法

        • 手动执行
        • 参数列表(可多次传入)
        let person = {
          name: '任先生'
        }
        
        function sayName(...args) {
          console.log(this.name)
          console.log(args) // ["hello", "world", "lencamo"]
        }
        
        let newSayName = sayName.bind(person, 'hello', 'world')
        newSayName('lencamo')
        

        # 4、区别汇总 🎈

        相同点:

        • 都可以改变 this 指向
        • 都可以传入参数

        不同点:

        • bind 返回的是一个新的函数,可以手动执行,也因此可以多次传入参数
        • apply 和 call 传入参数的方式不同,apply 传入数组,call 传入列表
        更新于 : 8/7/2024, 2:16:31 PM