这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
在JS的世界中,this指向无论工作中还是面试过程中都是一道非常重要的问题,this因其灵活的指向和复杂的使用场景变得千变万化,那么今天我们就来一起看看this
this指向谁
初学this的时候,为了方便理解和记忆,也为了应对面试,当讨论this指向谁的时候,总会拿出万能的总结:
谁调用它,那么this就指向谁,this的指向是在调用的时候确定的
初始这句话时,并没有发现其有什么问题,随着时间的推移、技术的深入了解后,发现并不能覆盖所遇到的this指向问题,渐渐的发现这句话的不严谨
this指向场景:
- 在函数体中,简单调用该函数时(非显式/隐式绑定下),严格模式下
this
绑定到undefined
,否则绑定到全局对象window
/global
; - 一般构造函数
new
调用,绑定到新创建的对象上; - 一般由
call
/apply
/bind
方法显式调用,绑定到指定参数的对象上; - 一般由上下文对象调用,绑定在该对象上;
- 箭头函数中,根据外层上下文绑定的
this
决定this
指向。
通过上述的场景,this的指向到底是如何确定的呢?
一句话总结:代码执行时,根据当前的执行上下文动态决定this的指向
实战分析
函数中
函数在浏览器全局环境中被简单调用,非严格模式下 this
指向 window
;在 use strict
指明严格模式的情况下就是 undefined
。例题:
const fn1 = function () {
console.log(this)
}
const fn2 = function () {
'use strict';
console.log(this)
}
fn1() // window
fn2() // undefined
对象中
const person = {
name: 'nordon',
say () {
console.log('this: ', this)
console.log('name: ',this.name)
}
}
// 直接调用
person.say()
// 将 person.say 赋值给say 然后调用
const say = person.say
say()
两种调用方式的结果是不一样的
person.say()
直接调用,这个时候函数中的this
的执行上下文是person
,因此输出person
和nordon
将 person.say
赋值给say
然后调用, 这里 this
仍然指向的是 window
。虽然 say
函数在 person
对象中作为方法被引用,但是在赋值给 say
之后,say
的执行仍然是在 window
的全局环境中。因此输出 window
和 undefined
显示改变this
在JS中call、apply、bind都是用来改变相关函数 this
指向的,但是 call/apply
是直接进行相关函数调用;bind
不会执行相关函数,而是返回一个新的函数,这个新的函数已经自动绑定了新的 this
指向,开发者需要手动调用即可。再具体的 call/apply
之间的区别主要体现在参数设定上
const person = {
name: 'nordon'
}
var name = 'window name'
const fn = function (env) {
console.log(`${env}: ${this.name}`)
}
fn('window') // window: window name
fn.call(person, 'call') // call: nordon
fn.apply(person, ['apply']) // apply: nordon
fn.bind(person)('bind') // bind: nordon
构造函数
想要搞懂构造函数中的this,需要知道当我们使用new关键字进行实例化的时候,在构造函数中做了哪些事情
- 创建一个新的对象 obj
- 将构造函数的this指向这个新的对象 obj
- 为这个新的对象添加属性、方法等
- 返回新的对象
function Person(name) {
console.log('this: ', this)
this.name = name
}
const p = new Person('nordon')
此时里面的this
输出为Person
,而非有些人认为的window
箭头函数
箭头函数使用 this
是根据外层(函数或者全局)上下文来决定。
const name = 'window name'
const person = {
name: 'nordon',
say: () => {
console.log('name: ', this.name)
}
}
person.say() // name: window name
const person2 = {
name: 'out name',
child: {
name: 'child namae',
say () {
console.log('name: ', this.name)
}
}
}
person2.child.say() // name: window name
此时this
指向的是window
,和普通的对象中直接调用时this
指向对象本身不同,而是根据person定义的环境决定的