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 相关文章推荐
经典的解除许多网站无法复制文字的绝招
Dec 31 Javascript
学习javascript,实现插入排序实现代码
Jul 31 Javascript
javascript实现window.print()去除页眉页脚
Dec 30 Javascript
解决bootstrap中modal遇到Esc键无法关闭页面
Mar 09 Javascript
基于Jquery easyui 选中特定的tab
Nov 17 Javascript
基于javascript实现泡泡大冒险网页版小游戏
Mar 23 Javascript
Bootstrap中点击按钮后变灰并显示加载中实例代码
Sep 23 Javascript
js中字符型和数值型数字的互相转化方法(必看)
Apr 25 Javascript
js移动端图片压缩上传功能
Aug 18 Javascript
jQuery中的$是什么意思及 $. 和 $().的区别
Apr 20 jQuery
Vue-cli项目部署到Nginx服务器的方法
Nov 01 Javascript
vue实现把接口单独存放在一个文件方式
Aug 13 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
Apache服务器无法使用的解决方法
2013/05/08 PHP
深入php list()函数的详解
2013/06/05 PHP
php版本的cron定时任务执行器使用实例
2014/08/19 PHP
基于jquery的一行代码轻松实现拖动效果
2010/12/28 Javascript
用js来定义浏览器中一个左右浮动元素相对于页面主体宽度的位置的函数
2012/01/21 Javascript
javascript里模拟sleep(两种实现方式)
2013/01/25 Javascript
将字符串转换成gb2312或者utf-8编码的参数(js版)
2013/04/10 Javascript
javascript ready和load事件的区别示例介绍
2013/08/30 Javascript
今天是星期几的4种JS代码写法
2013/09/17 Javascript
json实现前后台的相互传值详解
2015/01/05 Javascript
使用Javascript实现选择下拉菜单互移并排序
2016/02/23 Javascript
jQuery获取cookie值及删除cookie用法实例
2016/04/15 Javascript
JS+Canvas绘制时钟效果
2020/08/20 Javascript
浅谈jQuery中ajaxPrefilter的应用
2016/08/01 Javascript
JavaScript实现刷新不重记的倒计时
2016/08/10 Javascript
详解Javascript函数声明与递归调用
2016/10/22 Javascript
jQuery中$.ajax()方法参数解析
2016/10/22 Javascript
vue+element项目中过滤输入框特殊字符小结
2019/08/07 Javascript
JavaScript鼠标拖拽事件详解
2020/04/03 Javascript
js动态生成表格(节点操作)
2021/01/12 Javascript
python执行shell获取硬件参数写入mysql的方法
2014/12/29 Python
Python的Bottle框架中返回静态文件和JSON对象的方法
2015/04/30 Python
编写多线程Python服务器 最适合基础
2018/09/14 Python
Python实现FTP文件传输的实例
2019/07/07 Python
css3 矩阵的使用详解
2018/03/20 HTML / CSS
Laura官网:加拿大女性的顶级时尚目的地
2019/09/20 全球购物
STP的判定过程
2012/10/01 面试题
《听鱼说话》教学反思
2014/02/15 职场文书
霸王洗发水广告词
2014/03/14 职场文书
管理工程专业求职信
2014/08/10 职场文书
井冈山红色之旅心得体会
2014/10/07 职场文书
2015年采购工作总结
2015/04/10 职场文书
2015年学校办公室工作总结
2015/05/26 职场文书
小学教师师德培训心得体会
2016/01/09 职场文书
计算机实训心得体会
2016/01/14 职场文书
【海涛教你打DOTA】虚空假面第一视角骨弓3房29杀
2022/04/01 DOTA