5.深入理解箭头函数 - JS
什么是箭头函数?
箭头函数是指通过箭头函数表达式创建的函数,是匿名函数。
箭头函数表达式的语法更简洁,但语义有差异,所以用法上也有一些限制。尽管如此,箭头函数依旧被广泛运用在需要执行“小函数”的场景。
箭头函数表达式的基本语法:
/* 函数体只有一个语句 */
() => 单个语句
单个参数 => 单个语句
(单个参数) => 单个语句
(参数1, 参数2) => 单个语句
let f = ()=>console.log(111)
f() === undefined // true/* 函数体有多个语句,使用{} */
() => { 多个语句 }
单个参数 => { 多个语句 }
(单个参数) => { 多个语句 }
(参数1, 参数2) => { 多个语句 }
let g = ()=>{}
箭头函数表达式的语法说明:
- 只有一个参数时,
()
可以省略; - 函数体只有单个语句,
{}
可以省略,返回值就是该语句/表达式的值; - 函数体有多个语句,必须使用
{}
包围; - 语法上,返回一个对象字面量时,加
()
; - 箭头是复合符号,不要空格或换行;
- 参数列表和箭头之间不要换行;
- 箭头
=>
的优先级不高,在符合运算中尽量用()
包围。
let f = ()=>{ a:1 } // 不报错,a被当成一个标签,执行了表达式 “1”,返回 undefined
let f = ()=>{ a: 1, b: 2 } // 报错
let f = ()=>{ a: 1; b: 2 } // 不报错,a,b都时标签
let f = ()=>( {a:1, b:2} ) // 不报错,()改变了优先级let g = () = > {} // 报错
let g = () // 报错=> {}let x = f || ( ()=>{} )
箭头函数的限制:
- 箭头函数不绑定
this
,会捕获其声明所在上下文的this
,且call/apply/bind
方法都不会改变其指向; - 不能用作构造函数,不能使用
new
调用,会引发类型错误,函数体内也无法访问new.target
; - 不能使用
yield
,不能用做生成器函数; - 没有
arguments
对象,可以使用剩余参数取而代之; - 没有原型对象
prototype
这个属性。
this 的绑定问题
箭头函数没有独立的 this
,下面将依次总结其如何绑定上下文的 this
、避免用作方法等限制问题。
绑定上下文的 this
箭头函数捕获声明所在上下文的 this
并绑定,考虑捕获绑定顺序如下:
- 外层函数:内部的箭头函数和外部(临近)的普通函数有相同的
this
绑定; - 类:类具有封闭独立的
this
上下文,箭头函数作为方法时,将自动绑定实例的this
;本质就像闭包,有独立的变量环境,不会因为属性解构等操作改变其绑定。 - 全局:当以上不符合,一般和全局
globalThis
绑定。
由于箭头函数会绑定外部函数的 t h i s this this,所以在一些需要访问外部属性时常用,诸如函数 setTimeout/setInterval
、方法 forEach/map
等。下面一个例子中:
showGroup2
内部的箭头函数绑定的是外部函数的this
,指向 w b 对象 wb对象 wb对象,所以能够访问其属性group
;showGroup3
绑定的是全局(globalThis
),指向 全局对象 全局对象 全局对象,访问的是全局属性;convert
内部的箭头函数绑定的是 this.data 的this
,指向 w b 对象 wb对象 wb对象,能够正确访问属性group
;convert2
内部的箭头函数绑定的也是 this.data 的this
,但外部也是箭头函数,指向 全局对象 全局对象 全局对象,将会报错或者得到错误的结果,所以尽量不使用箭头函数作为方法。
const wb = {group: '第一组',data: [1, 2, 3, 4],showGroup: function () { console.log(this.group); },showGroup2: function () { (() => { console.log(this.group) })(); },showGroup3: () => { console.log(this.group) },convert: function() {let res = new Array;this.data.forEach( (elem)=>{ res.push(this.group + ':' + elem); } );return res;},convert2: () => {let res = new Array;// console.log(this == globalThis), // true// console.log(this.data); // undefined/其他this.data.forEach( (elem)=>{ res.push(this.group + ':' + elem); } );return res;},
}
类的封闭性使得箭头函数与实例自动绑定,每创建一个实例,都分配一个闭包,和实例环境自动绑定。下面一个例子中:
- 箭头函数
fa
绑定具体的实例对象,解构赋值不会改变 this 指向; - 普通方法
fd
在构造时绑定自身,解构赋值也不会改变 this 指向; - 另外的
fb/fc
作为普通方法,在构造时没有绑定自身,解构赋值会改变 this 指向。
class C {constructor() { this.fd = this.fd.bind(this) };a = 1;fa = ()=>{ console.log(this.a); };fb = function () { console.log(this.a); };fc () { console.log(this.a); };fd = function () { console.log(this.a); };
}let c = new C();
c.fa(); // 1
let { fa, fb, fc, fd } = c;
fa(); // 1
fb(); // 报错,属性未定义
fc(); // 报错,属性未定义
fd(); // 1
call、bind 和 apply 不会改变箭头函数的 this 指向
箭头函数表达式是执行完创建的,所以 this 绑定声明定义所在上下文的 this。call
、bind
和 apply
方法都不会改变其指向。下面一个例子中:
- 普通函数的
this
绑定,可以根据需求被call/apply/bind
改变,指向 o o o 对象; - 箭头函数的
this
绑定,不可以被call/apply/bind
改变,依旧指向全局对象。
const o = { a: 10 }
globalThis.a = 100;const add = function (m, n) { return this.a + m + n; }
const add2 = n => this.a + m + n;add.call(o, 2, 3) // 15
add.apply(o, [2, 3]) // 15
let boundedAdd = add.bind(o);
boundedAdd(2, 3) // 15add2.call(o, 2, 3) // 105
add2.apply(o, [2, 3]) // 105
let boundedAdd2 = add.bind(o);
boundedAdd2(2, 3) // 105
在 setTimeout 中使用箭头函数
setTimeout
函数,使用一定封闭环境内的属性时,常用箭头函数作为回调函数。下面一个例子中:
loading
中箭头函数,绑定外部方法loading
的this
,指向 o 对象 o对象 o对象;loading2
中由function
引导的声明式函数,将绑定全局(globalThis
),指向 全局对象 全局对象 全局对象;- setTimeout 不会影响内部箭头函数的 this 绑定,也不会影响内部普通函数的 this 绑定。
const o = {n: 0,loading () {setTimeout(() => {console.log(++this.n); // 箭头函数,this绑定声明所在上下文}, 1000)},loading2 () {setTimeout(function () { console.log(++this.n); // 声明式函数,this绑定提升到全局}, 1000)},
}o.loading() // 1秒后,控制台输出 1
o.loading() // 再1秒后,控制台输出 2
o.loading2() // 再1秒后,控制台输出 NaN 或其他
更一般的,在需要控制函数内 this
绑定指定区域时,采用箭头函数,一个例子如下:
const o = {n: 1,f() {let fn = function () { console.log(++this.n); }; // 声明式函数,this绑定提升到全局fn();},g() {let gn = () => { console.log(++this.n); }; // 箭头函数,this绑定声明所在上下文gn();},
}o.g() // 2
o.f() // NaN
不仅如此,箭头函数常出现在 promise
链中。或者说,箭头函数经常作为一个回调函数出现。
没有 arguments 对象
箭头函数没有自己的 arguments
对象。类似 this
的绑定,箭头函数会使用上下文 / 外部的 arguments
。下面一个例子中:
- 内部箭头函数与外部函数
f
的参数隐式绑定; - 即
arguments[0]
为f
的第一个参数n
。
function f(n) {let g = () => arguments[0] + n; // f 的隐式参数绑定。arguments[0] 为 f 的第一个参数 nreturn g();
}f(3); // 3 + 3 = 6
JS 类没有默认的 arguments
字段,下面的例子中:
- 全局箭头函数可以访问全局变量
arguments
(如果存在); - 类可以自定义
arguments
字段并进行访问(使用this
指定)。
globalThis.arguments = [1, 2, 3]
let f = () => { console.log(arguments[0]); }
class C {constructor(a, ...r) { this.arguments = [a, ...r]; };// arguments = [1, 2, 3];g = () => { console.log(this.arguments[0]); };
}f() // 1
(new C(10, 1, 2)).g() // 10
由于箭头函数的以上特性,在需要指定作用域的 this/arguments
时(setTimeout/Promise/闭包/装饰器/...
),能够起到简化的作用。下面一个装饰器的例子中:
- 内部箭头函数可以对外部函数的
this
和arguments
访问,
function sayHi(name) { console.log(`Hello, ${name}!`); }function decorator1(fn, ms) {return function () {setTimeout(() => fn.apply(this, arguments), ms); }
}function decorator2(fn, ms) {return function (...args) {let nt = this;setTimeout(function() { return f.apply(nt, args); }, ms);}
}let f = decorator1(sayHi, 1000);
let g = decorator2(sayHi, 1000);
f('Lily');
g('Jack');
在大多情况下,使用剩余参比使用 arguments
是更好的选择。
不能用作构造函数
- 箭头函数不能用作构造函数,当使用
new
调用时会出错。
const F = () => {this.a = 10;
}let f = new F() // 报错,不能作为构造器
- 更不允许在箭头函数中使用
new.target
。
const G = (v) => {if (!new.target) return new G(v); // 报错,不允许在箭头函数中出现 new.targetthis.k = v;
}
相关文章:
5.深入理解箭头函数 - JS
什么是箭头函数? 箭头函数是指通过箭头函数表达式创建的函数,是匿名函数。 箭头函数表达式的语法更简洁,但语义有差异,所以用法上也有一些限制。尽管如此,箭头函数依旧被广泛运用在需要执行“小函数”的场景。 箭头…...

高效的工作学习方法
1.康奈尔笔记法 在这里插入图片描述 2. 5W2H法 3. 鱼骨图分析法 4.麦肯锡7步分析法 5.使用TODOLIST 6.使用计划模板(年月周) 7. 高效的学习方法 成年人的学习特点: 快速了解一个领域方法 沉浸式学习方法: 沉浸学习的判据&am…...
【MySQL】-17 MySQL综合-3(MySQL创建数据库+MySQL查看数据库+MySQL修改数据库+MySQL删除数据库+MySQL选择数据库)
MySQL创建数据库查看数据库修改数据库删除数据库选择数据库 一 MySQL创建数据库实例1:最简单的创建 MySQL 数据库的语句实例2:创建 MySQL 数据库时指定字符集和校对规则 二 MySQL查看或显示数据库实例1:查看所有数据库实例2:创建并…...

【教学类-46-08】20240212立体鱼1.0
前期做了一个立体春字 作品展示 背景需求: 在南浔古镇的非遗文化馆里看到一个新年活动折纸——年年有鱼挂饰 我从网上搜索教程,完全可以用15*15的手工纸给孩子们做一套。 折纸教程 视频暂时不能查看https://haokan.baidu.com/v?pdwisenatural&vid1…...

【JVM篇】什么是jvm
文章目录 🍔什么是Java虚拟机🛸Java虚拟机有什么用🌹Java虚拟机的功能🎈Java虚拟机的组成 🍔什么是Java虚拟机 JVM指的是Java虚拟机,本质上是一个运行在计算机上的程序,可以运行 Java字节码文件…...

Vulnhub靶场 DC-9
目录 一、环境搭建 二、信息收集 1、主机发现 2、指纹识别 三、漏洞复现 1、dirsearch目录探测 2、sqlmap注入测试 3、文件包含漏洞 4、Knockd敲门服务 5、ssh爆破 6、提权 四、提取flag 一、环境搭建 Vulnhub靶机下载: 官网地址:https://…...
day2-理解 linux 云计算
1.解释服务器是什么; 服务器是一种高性能计算机,它的主要功能是提供计算服务和资源给其他计算机使用。在网络环境中,服务器扮演着重要的角色,它们可以存储和管理大量的数据,处理网络请求,提供应用程序运行…...
Android 13.0 开启禁用系统接收短信功能
1.概述 在13.0的系统rom定制化中,在一些wifi产品的机器中,对于系统4g部分的功能需要裁剪 比如拨打电话 接听电话 短信功能等这部分 需要禁用系统对应的功能,接下来就来初步分析下系统中接收短信部分功能,然后实现禁用接收短信功能 2.禁用和启用系统短信功能实现的核心类 …...

compile error ESP32cam.h no such file or directory
解决方法 可以参考这篇文章: But first, you will need to download the esp32cam.h library. For this go to Github and download the esp32cam Zip. GitHub - yoursunny/esp32cam: OV2640 camera on ESP32-CAM, Arduino library 具体就是下面的这篇重要的文章 …...

使用 Chainlit, Langchain 及 Elasticsearch 轻松实现对 PDF 文件的查询
在我之前的文章 “Elasticsearch:与多个 PDF 聊天 | LangChain Python 应用教程(免费 LLMs 和嵌入)” 里,我详述如何使用 Streamlit,Langchain, Elasticsearch 及 OpenAI 来针对 PDF 进行聊天。在今天的文章中…...

Gitee的使用教程(简单详细)
1.安装git(我的电脑自带git,我没弄这步QAQ) Git (git-scm.com)https://git-scm.com/ 安装好后在桌面点击鼠标右键会出现git GUI 和 git Bash(没有的话点击显示更多选项) 2.去gitee上注册一个账号 工作台 - Gitee.co…...

生成树(习题)
模板】最小生成树 生成树有两种方法,但是我只会克鲁斯卡尔算法,所以接下来下面的的题目都是按照这个算法来实现的,首先来见一下生么是这个算法,在之前的我写的一篇博客中有题使叫修复公路,其实这一题就是使用了这个算…...

ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions
异常处理模型详解之异常处理概述 一,异常处理相关概念二,异常处理概述 一,异常处理相关概念 在介绍异常处理之前,有必要了解一些关于异常处理状态的术语: 当处理器响应一个异常时,我们称该异常被获取了&a…...
Ubuntu 18.04上安装cuDNN 8.9.6.50:一站式指南
Content 一、前言二、准备工作三、安装步骤1. 启用本地仓库2. 导入CUDA GPG密钥3. 更新仓库元数据4. 安装运行时库5. 安装开发者库6. 安装代码示例7. 另外一种安装办法 四、验证安装1. 验证cuDNN版本2. 测试示例代码 五、总结 一、前言 在深度学习领域,高效的计算资…...

Microsoft Word 超链接
Microsoft Word 超链接 1. 取消超链接2. 自动超链接2.1. 选项2.2. 校对 -> 自动更正选项2.3. Internet 及网络路径替换为超链接 References 1. 取消超链接 Ctrl A -> Ctrl Shift F9 2. 自动超链接 2.1. 选项 2.2. 校对 -> 自动更正选项 2.3. Internet…...

SparkJDBC读写数据库实战
默认的操作 代码val df = spark.read.format("jdbc").option("url", "jdbc:postgresql://localhost:5432/testdb").option("user", "username").option("password", "password").option("driver&q…...
代码随想录 -- 数组
文章目录 二分查找题目描述题解 移除元素题目描述题解:暴力解法题解:双指针法 有序数组的平方题目描述题解:暴力解法题解:双指针法 长度最小的子数组题目描述题解:暴力解法题解:滑动窗口(双指针…...

【国产MCU】-CH32V307-基本定时器(BCTM)
基本定时器(BCTM) 文章目录 基本定时器(BCTM)1、基本定时器(BCTM)介绍2、基本定时器驱动API介绍3、基本定时器使用实例CH32V307的基本定时器模块包含一个16 位可自动重装的定时器(TIM6和TIM7),用于计数和在更新新事件产生中断或DMA 请求。 本文将详细介绍如何使用CH32…...
Node.js开发-fs模块
这里写目录标题 fs模块1) 文件写入2) 文件写入3) 文件移动与重命名4) 文件删除5) 文件夹操作6) 查看资源状态7) 相对路径问题8) __dirname fs模块 fs模块可以实现与硬盘的交互,例如文件的创建、删除、重命名、移动等,还有文件内容的写入、读取ÿ…...

探索Nginx:强大的开源Web服务器与反向代理
一、引言 随着互联网的飞速发展,Web服务器在现代技术架构中扮演着至关重要的角色。Nginx(发音为“engine x”)是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。Nginx因其卓越的性能、稳定性和灵活性&…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...