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

本文实例讲述了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.jb51.net/code/HtmlJsRun测试上述代码运行效果。

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

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

(0)

相关推荐

  • JavaScript中的普通函数和箭头函数的区别和用法详解

    最近被问到了一个问题: javaScript 中的箭头函数 ( => ) 和普通函数 ( function ) 有什么区别? 我当时想的就是:这个问题很简单啊~(flag),然后做出了错误的回答-- 箭头函数中的 this 和调用时的上下文无关,而是取决于定义时的上下文 这并不是很正确的答案--虽然也不是完全错误 箭头函数中的 this 首先说我的回答中没有错误的部分:箭头函数中的 this 确实和调用时的上下文无关 function make () { return ()=>{ consol

  • JavaScript箭头函数中的this详解

    前言 箭头函数极大地简化了this的取值规则. 普通函数与箭头函数 普通函数指的是用function定义的函数: var hello = function () { console.log("Hello, Fundebug!"); } 箭头函数指的是用=>定义的函数: var hello = () => { console.log("Hello, Fundebug!"); } JavaScript箭头函数与普通函数不只是写法上的区别,它们还有一些微妙的不

  • 深入理解JavaScript中的箭头函数

    从一开始箭头就是 JavaScript 的一部分,在第一个 JavaScript 中就建议将内联的脚本代码包裹在 HTML 的注释中,这可以防止那些不支持 JavaScript 的浏览器错误滴将你的代码显示为明文.你也许写过下面这样的代码: <script language="javascript"> <!-- document.bgColor = "brown"; // red // --> </script> <scri

  • javascript ES6中箭头函数注意细节小结

    前言 ES6标准新增了一种新的函数:Arrow Function(箭头函数). 为什么叫Arrow Function?因为它的定义用的就是一个箭头: x => x * x 上面的箭头函数相当于: function (x) { return x * x; } 但箭头函数带来了些许问题,下面来一起看看吧. 关于{} 第一个问题是关于箭头函数与{}. 箭头函数,乍一看,用法似乎很简单,比如像下面这样用来给数组每一项乘以2: const numbers = [1, 2, 3]; const result

  • 深入理解JavaScript 箭头函数

    JavaScript箭头函数是ECMAScript 6中引入的编写函数表达式的一种简便方法.通常,在JavaScript中,可以通过两种方式创建函数: 函数语句. 函数表达式. 可以如下所示创建函数语句: function add(num1, num2) { var res = num1 + num2; return res; } var sum = add(7, 2); console.log(sum); 也可以创建相同功能的函数表达式,如下所示: var add = function (nu

  • JavaScript ES6箭头函数使用指南

    胖箭头函数(Fat arrow functions),又称箭头函数,是一个来自ECMAScript 2015(又称ES6)的全新特性.有传闻说,箭头函数的语法=>,是受到了CoffeeScript 的影响,并且它与CoffeeScript中的=>语法一样,共享this上下文. 箭头函数的产生,主要由两个目的:更简洁的语法和与父作用域共享关键字this.接下来,让我们来看几个详细的例子. 新的函数语法 传统的JavaScript函数语法并没有提供任何的灵活性,每一次你需要定义一个函数时,你都必须

  • JavaScript基础之this和箭头函数详析

    箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this. 由于箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this),他们的第一个参数会被忽略. 前言 阅读下面的内容要先看下<你不知道的javascript(上)>中的第二部分:this和对象原型(里面对于this指向的理论部分主要来源于该书). 问题 这周在写代码的时候,听同事在说箭头函数无法更改this的指向,并且使用下面代码进行验证: // (1)

  • Javascript中 带名 匿名 箭头函数的重要区别(推荐)

    带名函数是指函数显示地给出了一个名字的函数,function abs(x){}.匿名函数是指函数只带有function这个关键字,而没有像abs这种函数名称的函数,如function(){}.ES6标准新增了一种新的函数:Arrow Function(箭头函数)箭头函数表面上相当于匿名函数,并且简化了函数定义.它们各自的区别是什么呢? 1 带名和匿名函数的区别 区别:匿名函数需要讲地址赋值给另一个变量let a,然后再用a来调用函数:而带名函数因为显示地给出了函数名称,所以可以直接用这个函数名称

  • 深入理解Javascript箭头函数中的this

    首先我们先看一段代码,这是一个实现倒数功能的类「Countdown」及其实例化的过程: function Countdown(seconds) { this._seconds = seconds; } Countdown.prototype._step = function() { console.log(this._seconds); if (this._seconds > 0) { this._seconds -= 1; } else { clearInterval(this._timer)

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

    本文实例讲述了JS箭头函数和常规函数之间的区别.分享给大家供大家参考,具体如下: 在 JavaScript 中,你可以通过多种方式去定义函数. 第一种常用的方法是使用关键字 function: // 函数声明 function greet(who) { return `Hello, ${who}!`; } // 函数表达式 const greet = function(who) { return `Hello, ${who}`; } 代码中的函数声明和函数表达式被称为"常规函数". 从

  • Node.js 缓冲区(Buffer)模块的方法及实例分析

    二进制流是大量的二进制数据的集合.由于通常情况下二进制流的大小挺大的,因此二进制流一般不会一起运送,而会在运输前切分成小块然后逐一发送. 当数据处理单元暂时不再接收其他数据流时,剩余的数据将会被保留在缓存中,直到数据处理单元准备好接收更多数据为止. Node.js 服务器一般需要在文件系统中进行读写,而文件在存储层面而言其实都是二进制流.除此之外,Node.js 还能与 TCP 流一起使用,让 TCP 流在不可靠的互联网络上提供可靠的端到端字节流保障通信. 发送给接收者的数据流会被缓冲,直到接收

  • JS扩展类,克隆对象与混合类实例分析

    本文实例讲述了JS扩展类,克隆对象与混合类.分享给大家供大家参考,具体如下: 1.类扩展 /* EditInPlaceField类 */ /* 扩展函数 */ function extend(subClass, superClass) { var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass

  • JS两种类型的表单提交方法实例分析

    本文实例分析了JS两种类型的表单提交方法.分享给大家供大家参考,具体如下: 1.原始的 <form method="post" action="/student/stureg/add" id="form1" onsubmit="return subForm();"> <button type="submit" class="button red" style="

  • js表单提交和submit提交的区别实例分析

    本文实例分析了js表单提交和submit提交的区别.分享给大家供大家参考,具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <

  • JS函数参数的传递与同名参数实例分析

    本文实例讲述了JS函数参数的传递与同名参数.分享给大家供大家参考,具体如下: 函数参数的传递 函数参数如果是原始类型值,传递方式是值传递.这意味着,在函数体内修改参数值,不会影响函数外部. var p = 2 function f(p) { p = 3 } f(p) p // 2 上面代码中,变量p是一个原始类型的值,传入函数f的方式是值传递,因此在函数内部,p的值是原始值的拷贝,无论怎么修改,都不会影响到原始值. 但是,如果函数参数是复合类型,传入函数的方式是引用的传递,也就是说,传入函数的是

  • JavaScript直接调用函数与call调用的区别实例分析

    本文实例讲述了JavaScript直接调用函数与call调用的区别.分享给大家供大家参考,具体如下: 直接调用 直接调用函数是最常见 最普通的方式,直接以函数附加的对象作为调用者, 在函数后括号内传入参数来调用函数 例如: window.alert("测试代码"); 其中调用者如果是window可以省略, 即直接alert("测试代码"); 以call() 方法调用函数 语法:call([thisObject[,arg1 [,arg2 [,...,argn]]]])

  • JavaScript中函数声明优先于变量声明的实例分析

    复制代码 代码如下: var a; // 声明一个变量,标识符为a function a() { // 声明一个函数,标示符也为a } alert(typeof a); 显示的是"function",即function的优先级高于var. 有人觉得这是代码顺序执行的原因,即a被后执行的funcion覆盖了.好,将它们调换下. 复制代码 代码如下: function a() { } var a; alert(typeof a); 结果仍然显示的是"function"而

  • JS对象和字符串之间互换操作实例分析

    本文实例讲述了JS对象和字符串之间互换操作.分享给大家供大家参考,具体如下: 平时在工作中大家一定也有过这样的需求,就是有时候需要把一个json对象转换为字符串,有时候要把一个类似json对象的字符串转换为json对象,那么今天就来总结一下,js的方法 1. json对象转字符串 这个API很简单就是 JSON.stringify() ,只需要把你要转换的对象写到括号里就行了,下面有一个小demo let json = { msg:"json转字符串", name:"前端林三

  • php 函数中静态变量使用的问题实例分析

    本文实例讲述了php 函数中静态变量使用的问题.分享给大家供大家参考,具体如下: <?php function msg() { static $a = 0; echo $a++, '<br />'; } msg(); msg(); msg(); 上述代码,分别输出0,1,2 静态变量$a在第一次定义并初始化后就会常驻内存,直到脚本执行完毕. 当第二次调用msg()函数时,这时的$a值为1,而不会变成0. 那么问题来了,请看下面的一段代码: $data = array( array('id

随机推荐