当前位置: 首页 > news >正文

一篇讲透:箭头函数、普通函数有什么区别

前言

 📫 大家好,我是南木元元,热衷分享有趣实用的文章,希望大家多多支持,一起进步!

 🍅 个人主页:南木元元


目录

什么是箭头函数

箭头函数和普通函数的区别

更简洁的语法

箭头函数没有自己的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框架时&#xff0c;你可以注册生命周期钩子来执行特定的逻辑。以下是一个示例&#xff0c;演示了如何在UniApp中使用Vue3框架注册生命周期钩子&#xff1a; <template> <view> <p>{{ message }}</p> </view> </templ…...

docker给容器分配固定ip

1.为 Docker 容器设置一个固定的 IP 地址 要为 Docker 容器设置一个固定的 IP 地址&#xff0c;有几种常见的方法&#xff1a; 使用自定义网络和静态 IP 地址&#xff1a; 你可以创建一个自定义的 Docker 网络&#xff0c;并在这个网络上为容器分配静态 IP 地址。首先&#x…...

Hadoop入门学习笔记——二、在虚拟机里部署HDFS集群

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

Spring之国际化:i18n

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…...

Java读取类路径下的JSON文件并转换为实体列表

使用 Jackson 库来读取类路径下的 JSON 文件并将其转换为对应实体列表。 在实际开发中可能在本地环境中需要调用别人的接口&#xff0c;别人的接口如果还没开发好或者本地环境不支持外部接口调用的时候&#xff0c;可以读取json文件来造数据&#xff0c;方便调试。 以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 是一个守护进程管理器&#xff0c;它将帮助您管理和保持您的应用程序在线。PM2 入门很简单&#xff0c;它以简单直观的 CLI 形式提供&#xff0c;可通过 NPM 安装。官网地址&#xff1a;https://pm2.keymetrics.io/ 二、问题&#xff1a;pm2日志内存占用过高&am…...

web3风险投资公司之Electric Capital

文章目录 什么是 Electric CapitalElectric团队 Electric Capital 开发者报告参考 什么是 Electric Capital 官网&#xff1a;https://www.electriccapital.com/ 官方github&#xff1a;https://github.com/electric-capital Electric Capital 是一家投资于加密货币、区块链企…...

为什么员工都非常抵触「绩效考核」,该怎么办呢?

员工抵制绩效考核的原因可能有很多&#xff0c;其中一些常见的原因包括&#xff1a; 考核方式不公正&#xff1a;如果考核方式不够客观、公正&#xff0c;或者与员工的实际工作情况不符&#xff0c;员工就会对绩效考核产生不信任感&#xff0c;从而产生抵触情绪。 工作压力增大…...

[node]Node.js 模块系统

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

【数据结构】什么是二叉树?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;二叉树的定义 &#x1f4cc;二叉树的特点 &#x1f4cc;特殊二叉树 &#x1f4cc;二叉树的性质 &#x1f4cc;二叉树的存储结构 &#x1f4cc;二叉树…...

C#教程(四):多态

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

电力系统风储联合一次调频MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 简介&#xff1a; 同一电力系统在不同风电渗透率下遭受同一负荷扰动时&#xff0c;其频率变化规律所示&#xff1a; &#xff08;1&#xff09;随着电力系统中风电渗透率的不断提高&#xff0c;风电零惯性响…...

《PCI Express体系结构导读》随记 —— 内容与作者简介

本书内容介绍 本书讲述了PCI与PCI Express总线相关的最为基础的内容&#xff0c;并介绍了一些必要的、与PCI总线相关的处理器体系结构知识&#xff0c;这也是本书的重点所在。深入理解处理器体系结构是理解PCI与PCI Express总线的重要基础。 读者通过对本书的学习&#xff0c…...

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&#xff08;闪电搜索器&#xff09;是一款使用多个(【支持Fofa、Shodan、Hunter、Zoomeye、360Quake网络空间搜索引擎】网络空间搜索引…...

Topaz Video AI 视频修复工具(内附安装压缩包win+Mac)

目录 一、Topaz Video AI 简介 二、Topaz Video AI 安装下载 三、Topaz Video AI 使用 最近玩上了pika1.0和runway的图片转视频&#xff0c;发现生成出来的视频都是有点糊的&#xff0c;然后就找到这款AI修复视频工具 Topaz Video AI。 一、Topaz Video AI 简介 Topaz Video…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

Python学习(8) ----- Python的类与对象

Python 中的类&#xff08;Class&#xff09;与对象&#xff08;Object&#xff09;是面向对象编程&#xff08;OOP&#xff09;的核心。我们可以通过“类是模板&#xff0c;对象是实例”来理解它们的关系。 &#x1f9f1; 一句话理解&#xff1a; 类就像“图纸”&#xff0c;对…...

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)

零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...

第22节 Node.js JXcore 打包

Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本&#xff0c;基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...

职坐标物联网全栈开发全流程解析

物联网全栈开发涵盖从物理设备到上层应用的完整技术链路&#xff0c;其核心流程可归纳为四大模块&#xff1a;感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性&#xff0c;例如传感器选型需平衡精度与…...

板凳-------Mysql cookbook学习 (十--2)

5.12 模式匹配中的大小写问题 mysql> use cookbook Database changed mysql> select a like A, a regexp A; ------------------------------ | a like A | a regexp A | ------------------------------ | 1 | 1 | --------------------------…...

SAP学习笔记 - 开发24 - 前端Fiori开发 Filtering(过滤器),Sorting and Grouping(排序和分组)

上一章讲了SAP Fiori开发的表达式绑定&#xff0c;自定义格式化等内容。 SAP学习笔记 - 开发23 - 前端Fiori开发 Expression Binding&#xff08;表达式绑定&#xff09;&#xff0c;Custom Formatters&#xff08;自定义格式化&#xff09;-CSDN博客 本章继续讲SAP Fiori开发…...