当前位置: 首页 > 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…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...