# 前言

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

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

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

# 一、this 关键字

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

# 1、this 认知

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

this.property
Copied!

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

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

var name = 'lencamo'

function sayName() {
  console.log(this.name) // 'lencamo'

  console.log(name) // 'lencamo'
}

sayName() // lencamo
Copied!

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

  通常情况下,对象方法中的 this 指向该对象。

let person = {
  name: '任先生',
  describe: function () {
    return this.name // this 指向 person对象
    // console.log(this === person) // true
  }
}
console.log(person.describe()) // 任先生
Copied!

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

function Person(name) {
  this.name = name // this 指向新生成的对象实例(具体如何理解可以去看看new的实现原理)
}

let p1 = new Person('任先生')

console.log(p1.name) // 任先生
Copied!

# 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)
}
Copied!

# 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: '黑狼王'
  }
]
Copied!

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')
Copied!

# 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')
Copied!

# 二、上下文函数

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

xxx(thisArg, ……)
Copied!

# 1、call 方法

  • 立即执行
  • 参数列表
let person = {
  name: '任先生'
}

function sayName(...args) {
  console.log(this.name)
  console.log(args) // ["hello", "world"]
}

sayName.call(person, 'hello', 'world')
Copied!

# 2、apply 方法

  • 立即执行
  • 参数数组
let person = {
  name: '任先生'
}

function sayName(...args) {
  console.log(this.name)
  console.log(args) // ["hello", "world"]
}

sayName.apply(person, ['hello', 'world'])
Copied!

# 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')
Copied!

# 4、区别汇总 🎈

相同点:

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

不同点:

  • bind 返回的是一个新的函数,可以手动执行,也因此可以多次传入参数
  • apply 和 call 传入参数的方式不同,apply 传入数组,call 传入列表
更新于 : 7/10/2025, 1:15:39 AM