JS箭头函数和常规函数之间的区别实例分析【 5 个区别】


Posted in Javascript onMay 27, 2020

本文实例讲述了JS箭头函数和常规函数之间的区别。分享给大家供大家参考,具体如下:

在 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 箭头函数

感谢类字段提案(目前在第3阶段),你可以将箭头函数用作类中的方法。

与常规函数相反,现在用箭头定义的方法能够把 this 词法绑定到类实例。

让我们把箭头函数作为字段:

class Hero {
 constructor(heroName) {
  this.heroName = heroName;
 }

 logName = () => {  
   console.log(this.heroName); 
 }
}

const batman = new Hero('Batman');

现在,你可以把 batman.logName 用于回调而无需手动绑定 thislogName() 方法中 this 的值始终是类实例:

setTimeout(batman.logName, 1000);
// after 1 second logs "Batman"

6. 总结

了解常规函数和箭头函数之间的差异有助于为特定需求选择正确的语法。

常规函数中的 this 值是动态的,并取决于调用方式。是箭头函数中的 this 在词法上是绑定的,等于外部函数的 this

常规函数中的 arguments 对象包含参数列表。相反,箭头函数未定义 arguments(但是你可以用剩余参数 ...args 轻松访问箭头函数参数)。

如果箭头函数有一个表达式,则即使不用 return 关键字也将隐式返回该表达式。

最后一点,你可以在类内部使用箭头函数语法定义去方法。粗箭头方法将 this 值绑定到类实例。

不管怎样调用胖箭头方法,this 始终等于类实例,在回调这些方法用时非常有用。

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
基于jquery自己写tab滑动门(通用版)
Oct 30 Javascript
关于js中for in的缺陷浅析
Dec 02 Javascript
IE8下Jquery获取select选中的值post到后台报错问题
Jul 02 Javascript
值得分享的Bootstrap Ace模板实现菜单和Tab页效果
Dec 30 Javascript
js实现简单的省市县三级联动效果实例
Feb 18 Javascript
jsTree使用记录实例
Dec 01 Javascript
jQuery实现扑克正反面翻牌效果
Mar 10 Javascript
JavaScript比较两个数组的内容是否相同(推荐)
May 02 Javascript
深入剖析Express cookie-parser中间件实现示例
Feb 01 Javascript
基于vue展开收起动画的示例代码
Jul 05 Javascript
Three.js中矩阵和向量的使用教程
Mar 19 Javascript
Vue登录主页动态背景短视频制作
Sep 21 Javascript
使用JavaScript获取Django模板指定键值数据
May 27 #Javascript
基于Vue CSR的微前端实现方案实践
May 27 #Javascript
Node.js API详解之 vm模块用法实例分析
May 27 #Javascript
jQuery实现鼠标滑动切换图片
May 27 #jQuery
js验证账户名是否重复
May 26 #Javascript
小程序富文本提取图片可放大缩小
May 26 #Javascript
微信小程序自定义联系人弹窗
May 26 #Javascript
You might like
php cout<<的一点看法
2010/01/24 PHP
PHP函数实现从一个文本字符串中提取关键字的方法
2015/07/01 PHP
thinkPHP中钩子的使用方法实例分析
2017/11/16 PHP
ThinkPHP框架实现FTP图片上传功能示例
2019/04/08 PHP
33种Javascript 表格排序控件收集
2009/12/03 Javascript
js textarea自动增高并隐藏滚动条
2009/12/16 Javascript
用js判断输入是否为中文的函数
2014/03/10 Javascript
javascript实现一个网页加载进度loading
2017/01/04 Javascript
angularjs使用directive实现分页组件的示例
2017/02/07 Javascript
详解vuex 中的 state 在组件中如何监听
2017/05/23 Javascript
微信小程序 选项卡的简单实例
2017/05/24 Javascript
JS简单获得节点元素的方法示例
2018/02/10 Javascript
微信小程序中实现手指缩放图片的示例代码
2018/03/13 Javascript
js构造函数constructor和原型prototype原理与用法实例分析
2020/03/02 Javascript
JavaScript, select标签元素左右移动功能实现
2020/05/14 Javascript
jquery轮播图插件使用方法详解
2020/07/31 jQuery
[01:07:41]IG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
详尽讲述用Python的Django框架测试驱动开发的教程
2015/04/22 Python
详解python字节码
2018/02/07 Python
Python+OpenCV实现车牌字符分割和识别
2018/03/31 Python
Python判断一个list中是否包含另一个list全部元素的方法分析
2018/12/24 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
Python aiohttp百万并发极限测试实例分析
2019/10/26 Python
python Opencv计算图像相似度过程解析
2019/12/03 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
Subside Sports德国:足球球衣和球迷商品
2019/06/08 全球购物
保送生自荐信范文
2013/10/06 职场文书
学生就业推荐信
2013/11/13 职场文书
北京大学自荐信范文
2014/01/28 职场文书
如何写好自荐信
2014/04/07 职场文书
仓库管理计划书
2014/05/04 职场文书
房屋鉴定委托书范本
2014/09/23 职场文书
2014年语文教师工作总结
2014/12/18 职场文书
2015学生会文艺部工作总结
2015/04/03 职场文书
SSM VUE Axios详解
2021/10/05 Vue.js
python数字图像处理之对比度与亮度调整示例
2022/06/28 Python