一篇讲透:箭头函数、普通函数有什么区别
前言
📫 大家好,我是南木元元,热衷分享有趣实用的文章,希望大家多多支持,一起进步!
🍅 个人主页:南木元元
目录
什么是箭头函数
箭头函数和普通函数的区别
更简洁的语法
箭头函数没有自己的this
箭头函数的this不会改变
箭头函数没有prototype属性
箭头函数不能作为构造函数
箭头函数不能使用arguments对象
箭头函数不能用作Generator函数
箭头函数不适用的场景
结语
什么是箭头函数
箭头函数是ES6(ECMAScript 6)新增的使用箭头(=>)语法定义函数表达式的能力。任何可以使用函数表达式的地方,都可以使用箭头函数,并且它的语法比传统的函数表达式更加简洁。
// 函数表达式
let functionExpressionSum = function(a, b) {return a + b;
}// 箭头函数
let arrowSum = (a, b) => {return a + b;
}
下面就来详细讲解一下箭头函数和普通函数的区别。
箭头函数和普通函数的区别
更简洁的语法
- 如果只有一个参数,可以不用括号。只有没有参数或多个参数的情况下,才需要使用括号。
// 只有一个参数,可以不用括号,以下两种写法都有效
let double = (x) => { return 2 * x; };
let triple = x => { return 3 * x; };// 没有参数需要括号
let getRandom = () => { return Math.random(); };// 多个参数需要括号
let sum = (a, b) => { return a + b; };// 无效的写法:
let multiply = a, b => { return a * b; };
- 如果函数体的返回值只有一句,可以省略大括号(省略大括号会隐式返回这行代码的值)。
// 以下两种写法都有效,而且返回相应的值
let double = (x) => { return 2 * x; };
let triple = (x) => 3 * x;// 无效的写法
let multiply = (a, b) => return a * b;
- 如果函数体不需要返回值,且只有一句话,可以给这个语句前面加一个void关键字。
// 最常见的就是调用一个函数
let fn = () => void doesNotReturn();
由于其更简洁的语法,箭头函数的一个用处就是简化回调函数。
// 普通函数写法
var result = arr.sort(function (a, b) {return a - b;
});// 箭头函数写法
var result = arr.sort((a, b) => a - b);
箭头函数没有自己的this
所有函数在执行时,会创建一个函数执行上下文,普通函数的执行上下文中会有一个变量this,而箭头函数没有,箭头函数不会创建自己的this对象,只会继承在自己作用域的上一层this。
var id = 'Global'// 箭头函数定义在全局作用域
let fun1 = () => {console.log(this.id)
}fun1() // 'Global'
输出:
可以⽤Babel理解⼀下箭头函数:
// ES6
const obj = { getArrow() { return () => { console.log(this === obj); }; }
}// 转化后的ES5
var obj = { getArrow: function getArrow() { var _this = this; return function () { console.log(_this === obj); }; }
};
上面代码中,转换后的ES5版本清楚地说明了,箭头函数里没有自己的this,而是引用外层的this。
箭头函数的this不会改变
箭头函数没有自己的this,所以箭头函数中this的指向在它定义时就已经确定了,之后不会改变。
var name = 'GLOBAL';
var obj = {name: '南木元元',getName1: function(){console.log(this.name);},getName2: () => {console.log(this.name);}
};
obj.getName1(); // '南木元元'
obj.getName2(); // 'GLOBAL'
输出结果:
对象obj的方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。所以其实定义对象的方法是不适合使用箭头函数的。
此外,call()、apply()、bind()等方法也不能改变箭头函数中this的指向。
var id = 'Global';
let fun1 = () => {console.log(this.id)
};
fun1(); // 'Global'
// this的指向不会改变
fun1.call({id: 'Obj'}); // 'Global'
fun1.apply({id: 'Obj'}); // 'Global'
fun1.bind({id: 'Obj'})(); // 'Global'
输出结果:
箭头函数没有prototype属性
来看下面代码。
let fn = function(name) {console.log(name);
}
let fn2 = name => console.log(name);
console.log(fn.prototype);
console.dir(fn2.prototype);
输出结果:
箭头函数不能作为构造函数
上面说了,箭头函数没有自己的this,没有prototype属性,所以也就不能用作构造函数,即不可以对箭头函数使用new
命令,否则会抛出错误。
let fn = (name, age) => {this.name = name;this.age = age;
}// 报错
let p = new fn('南木元元', 18);
输出结果:
为什么会这样呢?这其实跟new内部实现有关,new的实现步骤如下:
- 创建一个新的空对象
- 设置原型,将对象的原型设置为函数的prototype对象
- 让函数的this指向这个对象,执行构造函数的代码
- 返回新的对象
function myNew(constructor, ...args) {// 基于原型链 创建一个新对象,并且继承构造函数constructor的原型对象prototype上的属性let newObj = Object.create(constructor.prototype);// 执行构造函数,并让this指向这个新对象let res = constructor.apply(newObj, args); // 如果函数的执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象return typeof res === 'object' ? res: newObj;
}
上面的第二、三步,箭头函数都是没有办法执行的。
箭头函数不能使用arguments对象
arguments是一个对应于传递给函数的参数的类数组对象。
arguments是在所有普通函数中都可用的一个类数组对象,类数组不是数组,而是类似数组的对象,它除了length属性和索引之外,不能调用数组的方法。
所以通常会使用Array.prototype.slice.call(arguments)/Array.from(arguments)/[...arguments]的方式,将它转换成一个数组。
let fn = function () {console.log(arguments);console.log(Array.prototype.slice.call(arguments));
}
fn('param1', 'param2');
输出结果:
箭头函数不可以使用arguments对象,该对象在函数体内不存在。
let fn = (name, age) => console.log(arguments);
// 报错
fn('南木元元', 18);
输出结果:
在箭头函数中访问arguments实际上获得的是它外层函数的arguments值。
let fn = function(name, age) {let fn2 = name => {console.log(arguments);}fn2();
}
fn('南木元元', 18);
输出结果:
那么如果一定要用呢?可以用ES6中的rest参数代替。
let fn = (...args) => console.log(args);
fn('南木元元', 18);
输出结果:
上述代码使用了rest参数(形式为...变量名)获取函数的多余参数,这样就不需要使用arguments对象了。
箭头函数不能用作Generator函数
箭头函数内部不可以使用yield命令,因此箭头函数不能用作Generator函数。
let fn = function *() {yield '南木元元';
}
let p = fn();
console.log(p.next());
输出:
let fn = *() => {yield '南木元元';
}
let p = fn();
console.log(p.next());
输出:
箭头函数不适用的场景
- 对象方法,且方法内部使用this
第一个场景上面提到过,定义对象的方法并且方法内部使用this时不适合用箭头函数。
var name = 'GLOBAL';
var obj = {name: '南木元元',getName: () => {console.log(this.name);}
};
obj.getName(); // 'GLOBAL'
上述代码中,调用obj.getName()方法时,如果是普通函数,该方法内部的this指向调用它的那个对象;如果写成上面那样的箭头函数,使得this指向了全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致getName箭头函数定义时的作用域就是全局作用域。
- 需要动态this
第二个场合是需要动态this的时候,也不应使用箭头函数。
var button = document.getElementById('btn');
button.addEventListener('click', () => {console.log(this); //由于使用了箭头函数,this会指向全局对象Window
});
上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。
结语
本文主要总结了箭头函数和普通函数的几大区别,箭头函数虽然语法简洁,但也有一些场合不适用,需要根据不同的场景选择使用合适的函数。
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~
相关文章:

一篇讲透:箭头函数、普通函数有什么区别
前言 📫 大家好,我是南木元元,热衷分享有趣实用的文章,希望大家多多支持,一起进步! 🍅 个人主页:南木元元 目录 什么是箭头函数 箭头函数和普通函数的区别 更简洁的语法 箭头函数…...
第40节: Vue3 注册生命周期钩子
在UniApp中使用Vue3框架时,你可以注册生命周期钩子来执行特定的逻辑。以下是一个示例,演示了如何在UniApp中使用Vue3框架注册生命周期钩子: <template> <view> <p>{{ message }}</p> </view> </templ…...
docker给容器分配固定ip
1.为 Docker 容器设置一个固定的 IP 地址 要为 Docker 容器设置一个固定的 IP 地址,有几种常见的方法: 使用自定义网络和静态 IP 地址: 你可以创建一个自定义的 Docker 网络,并在这个网络上为容器分配静态 IP 地址。首先&#x…...

Hadoop入门学习笔记——二、在虚拟机里部署HDFS集群
视频课程地址:https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接:https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 Hadoop入门学习笔记(汇总) 目录 二、在虚拟机里部署HDFS集群2.1. 部署node1虚拟机2.2. 部…...

Spring之国际化:i18n
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...
Java读取类路径下的JSON文件并转换为实体列表
使用 Jackson 库来读取类路径下的 JSON 文件并将其转换为对应实体列表。 在实际开发中可能在本地环境中需要调用别人的接口,别人的接口如果还没开发好或者本地环境不支持外部接口调用的时候,可以读取json文件来造数据,方便调试。 以Student…...
复分析——第1章——复分析准备知识(E.M. Stein R. Shakarchi)
第一章 复分析准备知识 (Preliminaries to Complex Analysis) The sweeping development of mathematics during the last two centuries is due in large part to the introduction of complex numbers; paradoxically, this is based on the seemingly absurd no…...
C++ 继承方式
C++ 继承方式 实验介绍 本章节将学习权限关键字的使用,并将一一举例验证 public、protected、private 的使用,学完本小节实验后将彻底掌握权限关键字的使用。 知识点 权限关键字使用位置继承中的权限关键字public 继承protected 继承private 继承权限关键字使用位置 示例…...

华为云Windows Server服务器下,Node使用pm2-logrotate分割pm2日志,解决pm2日志内存占用过高的问题。
一、简介 PM2 是一个守护进程管理器,它将帮助您管理和保持您的应用程序在线。PM2 入门很简单,它以简单直观的 CLI 形式提供,可通过 NPM 安装。官网地址:https://pm2.keymetrics.io/ 二、问题:pm2日志内存占用过高&am…...

web3风险投资公司之Electric Capital
文章目录 什么是 Electric CapitalElectric团队 Electric Capital 开发者报告参考 什么是 Electric Capital 官网:https://www.electriccapital.com/ 官方github:https://github.com/electric-capital Electric Capital 是一家投资于加密货币、区块链企…...
为什么员工都非常抵触「绩效考核」,该怎么办呢?
员工抵制绩效考核的原因可能有很多,其中一些常见的原因包括: 考核方式不公正:如果考核方式不够客观、公正,或者与员工的实际工作情况不符,员工就会对绩效考核产生不信任感,从而产生抵触情绪。 工作压力增大…...

[node]Node.js 模块系统
[node]模块系统 Node.js中的模块系统模块的使用模块的导入模块的导出导出多个值导出默认值导出可传参的函数 文件查找策略从文件模块缓存中加载从原生模块加载从文件加载 Node.js中的模块系统 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。 …...

【数据结构】什么是二叉树?
🦄个人主页:修修修也 🎏所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 📌二叉树的定义 📌二叉树的特点 📌特殊二叉树 📌二叉树的性质 📌二叉树的存储结构 📌二叉树…...

C#教程(四):多态
1、介绍 1.1 什么是多态 在C#中,多态性(Polymorphism)是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息做出响应,即同一个方法可以在不同的对象上产生不同的行为。C#中的多态性可以通过以下几种方式实现…...

电力系统风储联合一次调频MATLAB仿真模型
微❤关注“电气仔推送”获得资料(专享优惠) 简介: 同一电力系统在不同风电渗透率下遭受同一负荷扰动时,其频率变化规律所示: (1)随着电力系统中风电渗透率的不断提高,风电零惯性响…...
《PCI Express体系结构导读》随记 —— 内容与作者简介
本书内容介绍 本书讲述了PCI与PCI Express总线相关的最为基础的内容,并介绍了一些必要的、与PCI总线相关的处理器体系结构知识,这也是本书的重点所在。深入理解处理器体系结构是理解PCI与PCI Express总线的重要基础。 读者通过对本书的学习,…...
C#字典和列表转LuaTable
C#字典和列表转LuaTable 将C#Dictionary转成luaTable将C#List转成luaTable 将C#Dictionary转成luaTable function DicToLuaTable(Dic)--将C#的Dic转成Lua的Tablelocal dic {}if Dic thenlocal iter Dic:GetEnumerator()while iter:MoveNext() dolocal k iter.Current.Keylo…...

动态内存管理(1)
目录 1. 为什么存在动态内存分配 2. 动态内存函数的介绍 2.2 calloc 2.3 realloc 3. 常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态开辟内存的一部分 3.5 对同一块动…...

ThunderSearch(闪电搜索器)_网络空间搜索引擎工具_信息收集
文章目录 ThunderSearch简介1 项目地址2 使用方式2.1 配置文件config.json说明2.2 构建和运行 3 使用式例 ThunderSearch简介 ThunderSearch(闪电搜索器)是一款使用多个(【支持Fofa、Shodan、Hunter、Zoomeye、360Quake网络空间搜索引擎】网络空间搜索引…...

Topaz Video AI 视频修复工具(内附安装压缩包win+Mac)
目录 一、Topaz Video AI 简介 二、Topaz Video AI 安装下载 三、Topaz Video AI 使用 最近玩上了pika1.0和runway的图片转视频,发现生成出来的视频都是有点糊的,然后就找到这款AI修复视频工具 Topaz Video AI。 一、Topaz Video AI 简介 Topaz Video…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...