箭头函数和常规函数之间的 5 个区别
wxin55 2024-11-26 09:42 7 浏览 0 评论
翻译:疯狂的技术宅
作者:Dmitri Pavlutin
来源:dmitripavlutin
转发链接:https://mp.weixin.qq.com/s/iHCyda-d9xwvnLWkcx0lLw
前言
在 JavaScript 中,你可以通过多种方式去定义函数。
第一种常用的方法是使用关键字 function:
// 函数声明
function greet(who) {
return `Hello, ${who}!`;
}
// 函数表达式
const greet = function(who) {
return `Hello, ${who}`;
}
代码中的函数声明和函数表达式被称为“常规函数”。
从 ES2015 开始,第二种可用的方法是 箭头函数 语法:
const greet = (who) => {
return `Hello, ${who}!`;
}
虽然两者的语法都能够定义函数,但是在开发时该怎么选择呢?这是个好问题。
在本文中,我将展示两者之间的主要区别,以供你能够根据需要选择正确的语法。
1. this 值
1.1常规函数
在常规 JavaScript 函数内部,this 值(即执行上下文)是动态的。
动态上下文意味着 this 的值取决于如何调用函数。在 JavaScript 中,有 4 种调用常规函数的方式。
在简单调用过程中,this 的值等于全局对象(如果函数在严格模式下运行,则为undefined ):
function myFunction() {
console.log(this);
}
// 简单调用
myFunction(); // logs global object (window)
在方法调用过程中,this 的值是拥有该方法的对象:
const myObject = {
method() {
console.log(this);
}
};
// 方法调用
myObject.method(); // logs "myObject"
在使用 myFunc.call(context, arg1, ..., argN) 或 myFunc.apply(context, [arg1, ..., argN]) 的间接调用中,this 的值等于第一个参数:
function myFunction() {
console.log(this);
}
const myContext = { value: 'A' };
myFunction.call(myContext); // logs { value: 'A' }
myFunction.apply(myContext); // logs { value: 'A' }
在使用关键字 new 的构造函数调用期间,this 等于新创建的实例:
function MyFunction() {
console.log(this);
}
new MyFunction(); // logs an instance of MyFunction
1.2箭头函数
箭头函数中 this 的行为与常规函数的 this 行为有很大不同。
无论如何执行或在何处执行,箭头函数内部的 this 值始终等于外部函数的 this值。换句话说,箭头函数可按词法解析 this,箭头函数没有定义自己的执行上下文。
在以下示例中,myMethod() 是箭头函数 callback() 的外部函数:
const myObject = {
myMethod(items) {
console.log(this); // logs "myObject"
const callback = () => {
console.log(this); // logs "myObject"
};
items.forEach(callback);
}
};
myObject.myMethod([1, 2, 3]);
箭头函数 callback() 中的 this 值等于外部函数 myMethod() 的 this。
this 词法解析是箭头函数的重要功能之一。在方法内部使用回调时,要确保箭头函数没有定义自己的 this:不再有 const self = this 或者callback.bind(this) 这种解决方法。
2.构造函数
2.1 常规函数
如上一节所述,常规函数可以轻松的构造对象。
例如用 Car() 函数创建汽车的实例:
function Car(color) {
this.color = color;
}
const redCar = new Car('red');
redCar instanceof Car; // => true
Car 是常规函数,使用关键字 new 调用时会创建 Car 类型的新实例。
2.2 箭头函数
this 此法解决了箭头函数不能用作构造函数。
如果你尝试调用带有 new 关键字前缀的箭头函数,则 JavaScript 会引发错误:
const Car = (color) => {
this.color = color;
};
const redCar = new Car('red'); // TypeError: Car is not a constructor
调用 new Car('red')(其中 Car 是箭头函数)会抛出 TypeError: Car is not a constructor。
3. arguments 对象
3.1 常规函数
在常规函数的主体内部,arguments 是一个特殊的类似于数组的对象,其中包含被调用函数的参数列表。
让我们用 3 个参数调用 myFunction 函数:
function myFunction() {
console.log(arguments);
}
myFunction('a', 'b'); // logs { 0: 'a', 1: 'b'}
类似于数组对象的 arguments 中包含调用参数:'a' 和 'b'。
3.2箭头函数
另一方面,箭头函数内部未定义 arguments 特殊关键字。
用词法解析 arguments 对象:箭头函数从外部函数访问 arguments。
让我们试着在箭头函数内部访问 arguments:
function myRegularFunction() {
const myArrowFunction = () => {
console.log(arguments);
}
myArrowFunction('c', 'd');
}
myRegularFunction('a', 'b'); // logs { 0: 'a', 1: 'b' }
箭头函数 myArrowFunction() 由参数 'c', 'd' 调用。在其主体内部,arguments 对象等于调用 myRegularFunction() 的参数:'a', 'b'。
如果你想访问箭头函数的直接参数,可以使用剩余参数 ...args:
function myRegularFunction() {
const myArrowFunction = (...args) => {
console.log(args);
}
myArrowFunction('c', 'd');
}
myRegularFunction('a', 'b'); // logs { 0: 'c', 1: 'd' }
剩余参数 ... args 接受箭头函数的执行参数:{ 0: 'c', 1: 'd' }。
4.隐式返回
4.1常规函数
使用 return expression 语句从函数返回结果:
function myFunction() {
return 42;
}
myFunction(); // => 42
如果缺少 return 语句,或者 return 语句后面没有表达式,则常规函数隐式返回undefined:
function myEmptyFunction() {
42;
}
function myEmptyFunction2() {
42;
return;
}
myEmptyFunction(); // => undefined
myEmptyFunction2(); // => undefined
4.2箭头函数
可以用与常规函数相同的方式从箭头函数返回值,但有一个有用的例外。
如果箭头函数包含一个表达式,而你省略了该函数的花括号,则将显式返回该表达式。这些是内联箭头函数
const increment = (num) => num + 1;
increment(41); // => 42
increment() 仅包含一个表达式:num + 1。该表达式由箭头函数隐式返回,而无需使用 return 关键字。
5. 方法
5.1 常规函数
常规函数是在类上定义方法的常用方式。
在下面 Hero 类中,用了常规函数定义方法 logName():
class Hero {
constructor(heroName) {
this.heroName = heroName;
}
logName() { console.log(this.heroName); }}
const batman = new Hero('Batman');
通常把常规函数用作方法。
有时你需要把该方法作为回调提供给 setTimeout() 或事件监听器。在这种情况下,你可能会很难以访问 this 的值。
例如用 logName() 方法作为 setTimeout() 的回调:
setTimeout(batman.logName, 1000);
// after 1 second logs "undefined"
1 秒钟后,undefined 会输出到控制台。setTimeout()执行 logName 的简单调用(其中 this 是全局对象)。这时方法会与对象分离。
让我们手动把 this 值绑定到正确的上下文:
setTimeout(batman.logName.bind(batman), 1000);
// after 1 second logs "Batman"
batman.logName.bind(batman) 将 this 值绑定到 batman 实例。现在,你可以确定该方法不会丢失上下文。
手动绑定 this 需要样板代码,尤其是在你有很多方法的情况下。有一种更好的方法:把箭头函数作为类字段。
5.2 箭头函数
感谢“类字段提案”(https://github.com/tc39/proposal-class-fields)(目前在第3阶段),你可以将箭头函数用作类中的方法。
与常规函数相反,现在用箭头定义的方法能够把 this 词法绑定到类实例。
让我们把箭头函数作为字段:
class Hero {
constructor(heroName) {
this.heroName = heroName;
}
logName = () => {
console.log(this.heroName);
}
}
const batman = new Hero('Batman');
现在,你可以把 batman.logName 用于回调而无需手动绑定 this。 logName()方法中 this 的值始终是类实例:
setTimeout(batman.logName, 1000);
// after 1 second logs "Batman"
6. 总结
了解常规函数和箭头函数之间的差异有助于为特定需求选择正确的语法。
常规函数中的 this 值是动态的,并取决于调用方式。是箭头函数中的 this 在词法上是绑定的,等于外部函数的 this。
常规函数中的 arguments 对象包含参数列表。相反,箭头函数未定义arguments(但是你可以用剩余参数 ...args 轻松访问箭头函数参数)。
如果箭头函数有一个表达式,则即使不用 return 关键字也将隐式返回该表达式。
最后一点,你可以在类内部使用箭头函数语法定义去方法。粗箭头方法将 this 值绑定到类实例。
不管怎样调用胖箭头方法,this 始终等于类实例,在回调这些方法用时非常有用。
推荐JavaScript经典实例学习资料文章
《通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events》
《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》
《JavaScript 已进入第三个时代,未来将何去何从?》
《前端上传前预览文件 image、text、json、video、audio「实践」》
《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》
《推荐13个有用的JavaScript数组技巧「值得收藏」》
《36个工作中常用的JavaScript函数片段「值得收藏」》
《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》
《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》
《JavaScript正则深入以及10个非常有意思的正则实战》
《前端开发规范:命名规范、html规范、css规范、js规范》
《100个原生JavaScript代码片段知识点详细汇总【实践】》
《手把手教你深入巩固JavaScript知识体系【思维导图】》
《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》
《身份证号码的正则表达式及验证详解(JavaScript,Regex)》
《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》
《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》
《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《面试中教你绕过关于 JavaScript 作用域的 5 个坑》
翻译:疯狂的技术宅
作者:Dmitri Pavlutin
来源:dmitripavlutin
转发链接:https://mp.weixin.qq.com/s/iHCyda-d9xwvnLWkcx0lLw
相关推荐
- 黑客工具sqlmap,带你了解什么师sql注入
-
1、sqlmap介绍sqlmap是一款支持MySQL,Oracle,PostgreSQL,MicrosoftSQLServer,MicrosoftAccess,IBMDB2,SQL...
- Web网络安全漏洞分析,SQL注入原理详解
-
本文主要为大家介绍了Web网络安全漏洞分析SQL注入的原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪一、SQL注入的基础1.1介绍SQL注入SQL注入就是指We...
- sql注入、文件上传、文件包含(sql注入数据提交的类型)
-
在owasp年度top10安全问题中,注入高居榜首。SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要...
- 比较常见类型漏洞讲解(三):SQL注入(一)
-
比较常见类型漏洞讲解(一)比较常见类型漏洞讲解(二):文件上传这里继续介绍比较容易找到的不同类型的漏洞。演示准备目标主机:Metasploitable2攻击目标:目标主机的dvwa系统攻击机:Kali...
- 警惕SQL注入:检测与防御的实战指南
-
在当今数字化的时代,软件系统的安全性至关重要。SQL注入作为一种常见且危害巨大的安全漏洞,给企业和用户带来了潜在的风险。对于测试人员来说,掌握发现和解决SQL注入漏洞的方法是保障软件质量和安全的...
- SQL注入的原理和危害(sql注入的原理及危害)
-
什么是SQL注入SQL注入是发生在web端的安全漏洞,实现非法操作,欺骗服务器执行非法查询,他的危害有会恶意获取,甚至篡改数据库信息,绕过登录验证,原理是针对程序员编写时的疏忽,通过执行SQL语句,实...
- 科普基础 | 最全的SQL注入总结(sql注入是干嘛的)
-
0x01SQL注入原理当客户端提交的数据未作处理或转义直接带入数据库,就造成了sql注入。攻击者通过构造不同的sql语句来实现对数据库的任意操作。0x02SQL注入的分类按变量类型分:数字型和字符...
- 产品经理必备IT技术知识之“什么是SQL注入攻击?
-
不少优秀的产品经理都会写一些简单的SQL语句进行数据查询的操作,但是会写SQL语句不代表能写好SQL语句。SQL语句写得不好,就会引发SQL注入攻击。SQL注入攻击是Web开发中最常见的一种安全问题,...
- 通过sql注入获取用户名和密码(联通光猫超级用户名超级密码获取)
-
1.啥是sql注入sql注入是一种通过操作输入来修改后台sql语句以达到利用代码进行攻击目的的技术2.生成sql注入漏洞的原因总结一句话:对前台传过来的参数没有进行有效的过滤,太相信前端传过来的参数...
- 什么是SQL注入攻击(SQL Injection)
-
1,定义:在构建数据库SQL语句时,攻击者在参数请求中注入恶意的SQL代码,并在在数据库中执行,操控数据库执行意图之外的操作。2,目的:窃取数据、修改数据、删除数据、绕过身份验证、权限提升,执...
- 浅谈SQL注入(sql注入的理解)
-
在关于SQL注入,百度的解释是这样的:SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知...
- sql注入(sql注入攻击是什么意思)
-
SQL注入分类1.数字型注入当输入的参数为整型时,则有可能存在数字型注入漏洞。假设存在一条URL为:HTTP://www.aaa.com/test.php?id=1可以对后台的SQL语句猜...
- SQL注入详解(sql注入总结)
-
现在大多数系统都使用B/S架构,出于安全考虑需要过滤从页面传递过来的字符。通常,用户可以通过以下接口调用数据库的内容:URL地址栏、登陆界面、留言板、搜索框等。这往往会出现安全隐患,为了更好的保护数据...
- 什么是sql注入,这些坑得避开(什么是sql注入,编程时如何避免)
-
1、sql注入是什么sql注入就是用户通过输入的参数,拼接到原先的sql中,成为sql的一部分,从而影响sql的功能和执行结果2、sql注入破坏力-小兵破坏力比如原先sql如下s...
- 金母鸡量化教学场:pandas—数据挖掘的Python库
-
如果你想充分发挥Python的强大作用,如果你想成为一名好的Python量化师,你应该先学好Pandas。今天就来了解什么是Pandas。与numpy易于处理同种类型数据不同,pandas更加的适合...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- hive行转列函数 (63)
- sourcemap文件是什么 (54)
- display none 隐藏后怎么显示 (56)
- 共享锁和排他锁的区别 (51)
- httpservletrequest 获取参数 (64)
- jstl包 (64)
- qsharedmemory (50)
- watch computed (53)
- java中switch (68)
- date.now (55)
- git-bash (56)
- 盒子垂直居中 (68)
- npm是什么命令 (62)
- python中+=代表什么 (70)
- fsimage (51)
- nginx break (61)
- mysql分区表的优缺点 (53)
- centos7切换到图形界面 (55)
- 前端深拷贝 (62)
- kmp模式匹配算法 (57)
- jsjson字符串转json对象 (53)
- jdbc connection (61)
- javascript字符串转换为数字 (54)
- mybatis 使用 (73)
- 安装mysql数据库 (55)