# 前言
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 传入列表