JavaScript中的this指向问题详解
作者:MoonBall 发布时间:2024-04-28 09:46:58
前言
相信我,只要记住本文的 7️⃣ 步口诀,就能彻底掌握 JS 中的 this 指向。
先念口诀:箭头函数、new、bind、apply 和 call、欧比届点(obj.)、直接调用、不在函数里。
按照口诀的顺序,只要满足前面某个场景,就可以确定 this 指向了。
接下来按照口诀顺序对它们进行详解,文中示例代码都运行在 Chrome 的 Console 控制台中。
文末有精心准备的练习题,用于检验学习成果,别忘了试试~
1. 箭头函数
箭头函数排在第一个是因为它的 this 不会被改变,所以只要当前函数是箭头函数,那么就不用再看其他规则了。
箭头函数的 this 是在创建它时外层 this 的指向。这里的重点有两个:
创建箭头函数时,就已经确定了它的 this 指向。
箭头函数内的 this 指向外层的 this。
所以要知道箭头函数的 this 就得先知道外层 this 的指向,需要继续在外层应用七步口诀。
2. new
当使用 new 关键字调用函数时,函数中的 this 一定是 JS 创建的新对象。
读者可能会有疑问,“如果使用 new 关键调用箭头函数,是不是箭头函数的 this 就会被修改呢?”。
我们在控制台试一下。
func = () => {}
new func() // throw error
从控制台中可以看出,箭头函数不能当做构造函数,所以不能与 new 一起执行。
3. bind
bind 是指 Function.prototype.bind() 。
多次 bind 时只认第一次 bind 的值
易错点
function func() {
console.log(this)
}
func.bind(1).bind(2)() // 1
箭头函数中 this 不会被修改
bind 与 new
易错点
function func() {
console.log(this, this.__proto__ === func.prototype)
}
boundFunc = func.bind(1)
new boundFunc() // Object true,口诀 2 优先
4. apply 和 call
apply() 和 call() 的第一个参数都是 this,区别在于通过 apply 调用时实参是放到数组中的,而通过 call 调用时实参是逗号分隔的。
箭头函数中 this 不会被修改
易错点
func = () => {
// 这里 this 指向取决于外层 this,参考口诀 7 「不在函数里」
console.log(this)
}
func.apply(1) // Window,口诀 1 优先
bind 函数中 this 不会被修改
易错点
function func() {
console.log(this)
}
boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口诀 3 优先
5. 欧比届点(obj.)
function func() {
console.log(this.x)
}
obj = { x: 1 }
obj.func = func
obj.func() // 1
这里就不用代码例证箭头函数和 bind 函数的优先级更高了,有兴趣可自行尝试吧。
6. 直接调用
在函数不满足前面的场景,被直接调用时,this 将指向全局对象。在浏览器环境中全局对象是 Window,在 Node.js 环境中是 Global。
先来个简单的例子。
function func() {
console.log(this)
}
func() // Window
来一个复杂的例子,外层的 outerFunc 就起个迷惑目的。
function outerFunc() {
console.log(this) // { x: 1 }
function func() {
console.log(this) // Window
}
func()
}
outerFunc.bind({ x: 1 })()
7. 不在函数里
不在函数中的场景,可分为浏览器的 <script /> 标签里,或 Node.js 的模块文件里。
在 <script /> 标签里,this 指向 Window。
在 Node.js 的模块文件里,this 指向 Module 的默认导出对象,也就是 module.exports。
非严格模式
严格模式是在 ES5 提出的。在 ES5 规范之前,也就是非严格模式下,this 不能是 undefined 或 null。所以**在非严格模式下,通过上面七步口诀,如果得出 this 指向是 undefined 或 null,那么 this 会指向全局对象。**在浏览器环境中全局对象是 Window,在 Node.js 环境中是 Global。
例如下面的代码,在非严格模式下,this 都指向全局对象。
function a() {
console.log("function a:", this)
;(() => {
console.log("arrow function: ", this)
})()
}
a()
a.bind(null)()
a.bind(undefined)()
a.bind().bind(2)()
a.apply()
非严格模式下执行结果为:
在严格模式下,执行同样的代码进行对比。记住要一次性将所有代码复制粘贴到控制台中,才能运行在严格模式下(因为第一行 "use strict" 才会对后面的代码生效)。
"use strict"
function a() {
console.log("function a:", this)
;(() => {
console.log("arrow function: ", this)
})()
}
a()
a.bind(null)()
a.bind(undefined)()
a.bind().bind(2)()
a.apply()
严格模式下执行结果为:
七步口诀在严格模式下和非严格模式下都是完备的,只是在非严格模式下 null 或 undefined 会被转换为全局对象。所以我没有将这点列入口诀中。
做题复习
先背诵口诀再做题,“箭头函数、new、bind、apply 和 call、欧比届点(obj.)、直接调用、不在函数里”。
1. 下面代码执行后,func.count 值为多少?
function func(num) {
this.count++
}
func.count = 0
func(1)
答案
func.count 值为 0。
按照口诀,func() 调用时属于第 6 类「直接调用」。在非严格模式下,this 指向全局对象。this 跟 func 一点关系都没有,所以 func.count 保持不变。so easy。
2. 以下箭头函数中 this 指向谁呢?
obj = {
func() {
const arrowFunc = () => {
console.log(this._name)
}
return arrowFunc
},
_name: "obj",
}
obj.func()()
func = obj.func
func()()
obj.func.bind({ _name: "newObj" })()()
obj.func.bind()()()
obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()
答案
// obj
// undefined
// newObj
// undefined
// bindObj
是不是很简单,你学废了吗?
总结
来源:https://juejin.cn/post/6946021671656488991


猜你喜欢
- 这篇文章主要介绍了微信小程序 textarea 层级过高问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 本文用到的文件的下载地址百度网盘链接: https://pan.baidu.com/s/1tmpdEfAZKff5TOMAitUXqQ提取码
- 1.将下面一段代码插入<head>与</head>之间:<script> function&
- 本文实例讲述了Python实现处理管道的方法。分享给大家供大家参考。具体分析如下:Linux下的可以施展的最炫的魔法是什么?相信不同的人说法
- 一、前言近期在实际项目中使用到了PID控制算法,于是就该算法做一总结。二、PID控制算法详解2.1 比例控制算法例子: 假设一个水缸,需要最
- //--------------------弹出层------------------- //popDivId:弹出层div的ID //dr
- 使用BootstrapValidator进行注册校验和登录错误提示,具体内容如下1、介绍在AdminEAP框架中,使用了BootstrapV
- 反向单位矩阵单位矩阵即对角线为 1,如下:那么反向的单位矩阵就是反对角线为 1:左右镜像操作这里采用 numpy 实现。方案 1import
- #coding=utf8__author__ = 'Administrator'# 当函数的参数不确定时,可以使用*args
- 一、漏洞描述该漏洞在/install/index.php(index.php.bak)文件中,漏洞起因是$$符号使用不当,导致变量覆盖,以至
- Python decimal 模块Python中的浮点数默认精度是15位。Decimal对象可以表示任意精度的浮点数。getcontext函
- 前言损失函数在机器学习中用于表示预测值与真实值之间的差距。一般而言,大多数机器学习模型都会通过一定的优化器来减小损失函数从而达到优化预测机器
- 在使用python编程过程中,我们往往需要借助字典来提高编程效率。同时为了调试方便,我们希望将某些变量保存为中间文件。例如,在协同过滤算法中
- 本文实例为大家分享了python爬取哈尔滨天气信息的具体代码,供大家参考,具体内容如下环境:windows7python3.4(pip in
- 1. 代码讲解1.1 导库import os.pathfrom os import listdirimport numpy as npimp
- 前言去年暑假参加了一个比赛,比赛内容中需要确定目标的位置 本来想全用图像完成的,最后发现不是很符合要求。比完赛之后,就忙别的事了。直到现在突
- 导语轻松瘦 | 和闺蜜减肥的日常,谁说闺蜜是减肥路上的一座山?哈喽!大家好!我是木木子吖~小编有一个闺蜜,还是同一所学校读书毕业的,这体重在
- 1.算法:对于一组关键字{K1,K2,…,Kn}, 首先从K1,K2,…,Kn中选择最小值,假如它是 Kz,则将Kz与 K1对换;然后从K2
- 最近在使用爬虫爬取数据时,经常会返回403代码,大致意思是该IP访问过于频繁,被限制访问。限制IP访问网站最常用的反爬手段了,其实破解也很容
- 一、模块概述模块指的是包含python代码的文件,也就是一个.py文件就是一个模块。文件夹(directory)---->包(pack