理解这7点就能掌握 JS 中的 this 指向

news/2024/10/30 9:30:01/

f8ce8344eb8d0560bb9279cb1a25a5e6.png

相信我,只要记住本文的 7️⃣ 步口诀,就能彻底掌握 JS 中的 this 指向。先念口诀:箭头函数、new、bind、apply 和 call、欧比届点(obj.)、直接调用、不在函数里。按照口诀的顺序,只要满足前面某个场景,就可以确定 this 指向了。接下来按照口诀顺序对它们进行详解,文中示例代码都运行在 Chrome 的 Console 控制台中。

1. 箭头函数

箭头函数排在第一个是因为它的 this 不会被改变,所以只要当前函数是箭头函数,那么就不用再看其他规则了。箭头函数的 this 是在创建它时外层 this 的指向。这里的重点有两个:

  1. 创建箭头函数时,就已经确定了它的 this 指向。

  2. 箭头函数内的 this 指向外层的 this

所以要知道箭头函数的 this 就得先知道外层 this 的指向,需要继续在外层应用七步口诀。

2. new

当使用 new 关键字调用函数时,函数中的 this 一定是 JS 创建的新对象。读者可能会有疑问,“如果使用 new 关键调用箭头函数,是不是箭头函数的 this 就会被修改呢?”。我们在控制台试一下。

func = () => {}
new func() // throw error
34728ee97fc48e07125fa460fed5b935.png

从控制台中可以看出,箭头函数不能当做构造函数,所以不能与 new 一起执行。

3. bind

bind 是指 Function.prototype.bind()。多次 bind 时只认第一次 bind 的值

易错点

function func() {console.log(this)
}func.bind(1).bind(2)() // 1

箭头函数中 this 不会被修改

func = () => {
// 这里 this 指向取决于外层 this,参考口诀 7 「不在函数里」console.log(this)
}func.bind(1)() // Window,口诀 1 优先

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 的模块文件里。

1、在 <script /> 标签里,this 指向 Window。

2、在 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()

非严格模式下执行结果为:

2c63aa48098ba471fb4a248f8eaa68f6.png

在严格模式下,执行同样的代码进行对比。记住要一次性将所有代码复制粘贴到控制台中,才能运行在严格模式下(因为第一行 "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()

严格模式下执行结果为:

79ffa35c797b461f16925a24aace7305.png

七步口诀在严格模式下和非严格模式下都是完备的,只是在非严格模式下 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

作者:MoonBall

https://juejin.cn/post/6946021671656488991


http://www.ppmy.cn/news/280462.html

相关文章

js 原型相关知识点总结

一、相关资料 JS原型链与继承别再被问倒了js构造函数详解一步步图解javascript的原型(prototype)对象,原型链进阶必读&#xff1a;深入理解 JavaScript 原型JS原型链简单图解JS 中 this 指向问题通俗易懂之JavaScript手动实现apply方法 二、技术点 1.构造函数&#xff08;co…

JS 中 this 指向问题

相信我&#xff0c;只要记住本文的 7️⃣ 步口诀&#xff0c;就能彻底掌握 JS 中的 this 指向。 先念口诀&#xff1a;箭头函数、new、bind、apply 和 call、欧比届点&#xff08;obj.&#xff09;、直接调用、不在函数里。 按照口诀的顺序&#xff0c;只要满足前面某个场景&…

【历史上的今天】11 月 7 日:图灵奖女性得主诞生;Twitter 告别 140 字符时代;首位中国 AI 主播

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2021 年 11 月 7 日&#xff0c;在 1867 年的今天&#xff0c;居里夫人诞生&#xff1b;居里夫人是法国的著名科学家&#xff0c;研究放射性现象&#xff0c;发现镭和钋…

程序员要学会读源代码

原文作者&#xff1a;Jeff Atwood 在“沟通”这个复杂的领域里&#xff0c;写出能让人类领会并理解的连贯段落比敲出几行让解释器或编译器不致于“呕吐”的软件代码要难得多。 这就是为什么——就软件开发而言——所有的文档大概都是很差劲的。而且&#xff0c;由于为人写作比…

外架小横杆外露长度规范要求_外架小横杆外露长度

2020-04-21施工工地安全体验区 湖南安全体验区厂家 汉坤实业提供全国工地安全体验区建设,厂家直销,好看不贵包安装。 施工工地安全体验区 湖南安全体验区 安全文明施工标准化管理手册摘选: 5.4.5、架体防护外侧防护脚手架的钢管应横平竖直转角处的大横杆伸出长度不能超…

【技术专家】技术专家的经典错误

史蒂夫乔布斯爱上了它&#xff0c;其他 的创始人史蒂夫休厄尔和无数其他人也爱上了它。但避免它只需要一个简单的思维转变。 软件开发人员等工程类型的灵感来自于构建事物固有的可能性。这种灵感永远将他们带入一个经典的错误中&#xff0c;这会带来困难和遗憾&#xff0c;并有…

前端面试问题(适用于面试回答思路)

箭头函数、普通函数、构造函数 js构造函数详解 js中箭头函数和普通函数的区别 箭头函数特点&#xff1a; 1&#xff09;箭头函数内部的this对象&#xff0c;就是函数上下文中的对象&#xff0c;而不是调用时的对象&#xff0c;不能用call&#xff0c;appply等方法改变this指向…

用串口修改ARM的IP地址

要修改ARM开发板的IP&#xff0c;如果是yaffs2文件&#xff0c;可以 1、首先要修改/etc/init.d/rcS文件&#xff0c;在/sbin/ifconfig lo 127.0.0.0 下添加一行/sbin/ifconfig eth0 192.168.1.112 up 注&#xff1a;192.168.1.112只是举例&#xff0c;可以改成你想要修改的I…