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