「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
this到底指向谁
this
在前端是一个很常见的关键字,我相信没人不知道。虽然很常见,但是这也是一个棘手的东西,稍不注意就写了bug
,通过本文,你将会更加彻底理解this
。
先上总结
想必很多人都听说,关于this
指向的一句话:“谁调用this
,this
就指向谁”
这句话本身是没毛病,但本文将会更加细致的具体的分析,看看在各种情况下this
的指向,这里大家伙先“死记硬背”以下几条法则
- 在函数体中,非显示或隐式调用函数时,严格模式下
this
会指向undefined
,非严格模式下会指向window/global
- 通常使用
new
调用构造函数时,构造函数内的this
会绑定到新实例对象上 - 通常通过
apply/call/bind
方法显示调用时,this
指向新传入的参数的对象上 - 一般通过上下文调用函数时,函数体内的
this
指向该上下文 - 箭头函数没有自己的
this
,this
的指向是由外层作用域决定
🌰例子
全局环境中的this
function f1() {
console.log(this)
}
function f2() {
'use strict'
console.log(this)
}
f1()
f2()
这个相信大家都懂了,f1()
输出window
,f2()
输出undefined
来个变种
const sister = {
name: '石原里美',
getName: function() {
console.log(this)
console.log(this.name)
}
}
const fn = sister.getName
fn()
答案
// window
// undefined
这里需要注意这里是赋值给一个变量,而这个变量是在windos
下定义,所以
这里的this
会指向window
,如果像下面直接调用,this
就指向调用它的这个对象sister
sister.getName()
new
中的this
function f1() {
this.food = '牛肉'
}
const f2 = new f1()
console.log(f2.food)
答案
// 牛肉
这里很好理解,new
构造函数,this
会指向新创建的实例上
再来一题
function f1() {
this.food = '牛肉'
return 0
}
function f2() {
this.food = '鸡肉'
return {}
}
const f3 = new f1()
const f4 = new f2()
console.log(f3.food)
console.log(f4.food)
答案
// 牛肉
// undefined
这里是不是出乎你的意料呢,这里有两个需要注意的点,如果这个构造函数显式的return
return
是值类型的话,this
会指向新创建的实例return
是引用类型,this
指向返回的这个对象
至于为什么会这样,建议可以看mdn关于new运算符的解释,和类型说明,本文就不展开阐述
上下文中的this
const sister = {
name: '桥本环奈',
actor: {
name: '石原里美',
getName: function () {
console.log(this.name)
}
}
}
sister.actor.getName()
答案
// 石原里美
this
会指向最后调用它的对象,就是actor
,所以输出就是石原里美
var f1 = {
text: '新年快乐 f1',
sayHi: function () {
return this.text
}
}
var f2 = {
text: '新年快乐 f2',
sayHi: function () {
return f1.sayHi()
}
}
var f3 = {
text: '新年快乐 f3',
sayHi:function () {
const sayHi = f1.sayHi
return sayHi()
}
}
console.log(f1.sayHi())
console.log(f2.sayHi())
console.log(f3.sayHi())
答案
// 新年快乐 f1
// 新年快乐 f1
// undefined
第一个比较简单,就是常规的调用,输入“新年快乐 f1”
第二个注意看调用的是谁,就很好理解,结果输入f1.text
的“新年快乐 f1”
最后一个可能会被迷惑,注意f1.sayHi
只是赋值,没有直接调用,然后返回一个函数的调用,重点这里是“裸奔”调用,sayHi
前面没有任何对象,相当于window.sayHi()
,所以输出undefined
call/apply/bind
中的this
这三个产生的作用都是相同的,都是通过新传入的参数,从而this
指向这个参数,只是这三个方法的调用稍有区别
function fn1() {
}
const obj = {}
fn1.call(obj, '新年快乐')
fn1.apply(obj, ['新年快乐']
fn1.bind(obj, '新年快乐')() // 注意bind绑定this,返回的是一个新对象
// 此时this指向obj
箭头函数中的this
const obj1 = {
text: 'ob1',
getText: () => {
console.log(this.text)
}
}
const obj2 = {
text: 'ob2',
getText: function() {
(() => console.log(this.text))()
}
}
obj1.getText()
obj2.getText()
答案
// undefined
// ob2
箭头函数,始终只要记住,this
的指向是由外层作用域决定的,而obj2.getText()
中,箭头函数外层是一个函数,这个函数的this
指向obj2
,所以输出是“ob2”
this的优先级
this
的绑定方法有new
,显式绑定(call/apply/bind)
,隐式绑定,如何确定优先级高低呢,光靠猜是不行的🤚🏼,实践出真章,通过下面例子一起进行探索
function fn1() {
console.log(this.a)
}
const obj1 = {
a: 1
}
const obj2 = {
a: 2
}
fn1()
fn1.call(obj1)
fn1.call(obj2)
答案
// undefined
// 1
// 2
通过例子可以看出call
方法显式绑定this
,优先级大于隐式绑定
来个变种
var a = 0
var fn1 = () => console.log(this.a)
const obj1 = {
a: 1,
}
const obj2 = {
a: 2,
}
fn1.call(obj1)
fn1.call(obj2)
答案
// 0
// 0
要注意到fn1
是一个箭头函数,然后通过call
修改this
的指向,输出依然是外层的a
,证明箭头函数的this
的绑定无法被修改
function food (text){
this.text = text
}
const obj = {}
var x = food.bind(obj)
x('鸡肉')
console.log(obj.text)
var y = new x()
console.log(y.text)
答案
// 鸡肉
// undefined
通过food.bind
的时候this
指向obj,当执行x('鸡肉')
的时候this.text
等于obj.text
所以输出“鸡肉”
通过new
运算符返回新的实例不指向obj
,所以输出undefined
所以得出结论new
>显式绑定>隐式绑定
参考
希望通过本文能够帮助到你,本人写作经验不多,如有表达不对之处,欢迎评论留言指出
首发于个人博客:小白带你理解this