JavaScript 箭头函数:适用与不适用场景

JavaScript 箭头函数:适用与不适用场景
现代 JavaScript 中最引人注目的功能之一是引入了箭头函数,用 => 来标识。

这种函数有两大优点 – 非常简洁的语法,和更直观的作用域和 this的绑定。

这些优点有时导致箭头函数比其他形式的函数声明更受欢迎。

例如,受欢迎的 airbnb eslint 配置 会在您创建匿名函数时强制使用JavaScript箭头函数。

然而,就像工程中的任何东西一样,箭头函数优点很明显,同时也带来了一些负面的东西。 使用他们的时候需要权衡一下。

学习如何权衡是更好地使用箭头函数的关键。

在本文中,我们将首先回顾箭头函数的工作原理,然后深入研究箭头函数改进代码的示例,最后深入研究箭不建议使用头函数的示例。

JavaScript 箭头函数究竟是什么?
JavaScript 箭头函数大致相当于 python 中的 lambda 函数 或 Ruby 中的 blocks。

这些是匿名函数,它们有自己的特殊语法,接受一定数量的参数,并在其封闭的作用域的上下文(即定义它们的函数或其他代码)中操作。

让我们依次分解这些部分。

箭头函数语法
箭头函数具有单一的总体结构,然后在特殊情况下可以通过多种方式简化它们。 核心结构如下所示:

(argument1, argument2, ... argumentN) => {
// function body
}
括号内的是参数列表,后跟“胖箭头”(=>),最后是函数体。

这与传统函数非常相似,我们只是省略 function 关键字并在参数后添加一个胖箭头(=>)。

然而,有许多方法可以简化箭头函数。

首先,如果函数体是单个表达式,则可以不使用花括号并将其置于内联中(省略大括号直接将表达式写在一行中)。 表达式的结果将由函数返回。 例如:

const add = (a, b) => a + b;
其次,如果只有一个参数,你甚至可以省略参数的括号。例如:

const getFirst = array => array[0];
正如您所看到的,这是一些非常简洁的语法,我们将重点介绍后面的好处。

高级语法
有一些高级语法可以了解一下。

首先,如果您尝试使用内联单行表达式语法,但您返回的值是对象字面量。您可能会认为这看起来应该是这样的:

(name, description) => {name: name, description: description};
问题是这种语法比较含糊不清,容易引起歧义 : 看起来好像你正试图创建一个传统的函数体。 如果你碰巧想要一个对象的单个表达式,请用括号包裹该对象:

(name, description) => ({name: name, description: description});
封闭的上下文作用域
与其他形式的函数不同,箭头函数没有自己的 执行期上下文。

实际上,这意味着 this 和 arguments 都是从它们的父函数继承而来的。

例如,使用和不使用箭头函数比较以下代码:

const test = {
name: ‘test object‘,
createAnonFunction: function() {
return function() {
console.log(this.name);
console.log(arguments);
};
},

createArrowFunction: function() {
return () => {
console.log(this.name);
console.log(arguments);
};
}
};
我们有一个简单的 test 对象,有两个方法 – 每个方法都返回一个匿名函数。

不同之处在于第一个方法使用传统函数表达式,而后者中使用箭头函数。

如果我们使用相同参数,在控制台中运行它们,我们会得到完全不一样的结果。

const anon = test.createAnonFunction(‘hello‘, ‘world‘);
const arrow = test.createArrowFunction(‘hello‘, ‘world‘);

anon();
undefined
{}

arrow();
test object
{ ‘0‘: ‘hello‘, ‘1‘: ‘world‘ }
第一个匿名函数有自己的函数上下文,因此当您调用它时,test 对象的 this.name 没有可用的引用,也没有创建它时调用的参数。

另一个,箭头函数具有与创建它的函数完全相同的函数上下文,使其可以访问 argumetns 和 test 对象。

使用箭头函数改进您的代码
传统 lambda 函数的主要用例之一,就是用于遍历列表中的项,现在用 JavaScript 箭头函数实现。

比如你有一个有值的数组,你想去 map 遍历每一项,这时使用箭头函数非常理想:

const words = [‘hello‘, ‘WORLD‘, ‘Whatever‘];
const downcasedWords = words.map(word => word.toLowerCase());
一个非常常见的例子是提取对象中的某个特定值:

const names = objects.map(object => object.name);
类似地,当用现代迭代样式取代传统的 for 循环,一般我们使用 forEach 循环,箭头函数能够保持 this 来自于父级,让他们非常直观

类似的,当用 forEach 来替换传统 for循环的时候,实际上箭头函数会直观的保持 this来自于父一级

this.examples.forEach(example => {
this.runExample(example);
});
Promises 和 Promise 链
箭头函数的另一个可以使代码更清晰,更直观的地方是管理异步代码。

Promises 使得管理异步代码变得容易很多(即使你很欢快地使用 async / await,你仍然应该理解 async / await 是建立在 Promises 之上的 !)

但是,虽然使用 promises 仍然需要定义在异步代码或调用完成后运行的函数。

这是箭头函数的理想位置,特别是如果您生成的函数是有状态的,同时想引用对象中的某些内容。 例如:

this.doSomethingAsync().then((result) => {
this.storeResult(result);
});
对象转换
箭头函数的另一个常见且极其强大的用途是封装对象转换。

例如,在 Vue.js 中,有一种通用模式,用于使用 mapState 将 Vuex 存储的各个部分直接包含到 Vue 组件中。

这涉及定义一组 “mappers” ,这些 “mappers” 将从原始的完整的 state 对象转换为提取所涉及组件所需的内容。

这些简单的转换使用箭头函数再合适不过了。比如:

export default {
computed: {
...mapState({
results: state => state.results,
users: state => state.users,
});
}
}
你不应该使用箭头函数的情景
在许多情况下,使用箭头函数不是一个好主意。 他们不仅不会帮助你,而且会给你带来一些不必要的麻烦。

第一个是对象的方法。 这是一个函数上下文的例子,这对于我们理解很有帮助。

有一段时间使用 Class(类)属性语法和箭头函数的组合,作为创建“自动绑定方法”的方式,例如, 事件处理程序可以使用,但仍然绑定到类的方法。

这看起来像是这样的:

class Counter {
counter = 0;

handleClick = () => {
this.counter++;
}
}
这样,即使 handleClick 由事件处理程序调用,而不是在 Counter 实例的上下文中调用,它仍然可以访问实例的数据。

这种方法的缺点很多,在本文中很好地记录。

虽然使用这种方法确实为您提供了具有绑定函数的快捷方式,但该函数以多种不直观的方式运行,如果您尝试将此对象作为原型进行子类化/使用,则会不利于测试,同时也会产生很多问题。

相反,使用常规函数,如果需要,将其绑定到构造函数中的实例:

class Counter {
counter = 0;

handleClick() {
this.counter++;
}

constructor() {
this.handleClick = this.handleClick.bind(this);
}
}
深层的调用链
箭头函数可能让你遇到麻烦的另一个地方是,它们被用于许多不同的组合,特别是在函数深层调用链中。

核心原因与匿名函数相同 – 它们给出了非常糟糕的堆栈跟踪。

如果你的函数只是向下一级,比如在迭代器里面,那也不是太糟糕,但是如果你把所有的函数定义为箭头函数,并在它们之间来回调用,你就会陷入困境 遇到一个错误的时候,只是收到错误消息,如:

{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
有动态上下文的函数
箭头函数可能让您遇到麻烦的最后一种情况就是吗, this 是动态绑定的时候。

如果您在这些位置使用箭头函数,那么动态绑定将不起作用,并且你(或稍后使用你的代码的其他人)可能会对事情未按预期执行的原因感到困惑。

一些典型的例子:

事件处理程序是通过将 this 设置为事件的 currentTarget 属性来调用。
如果您仍在使用 jQuery ,则大多数 jQuery 方法将 this 设置为已选择的 dom 元素。
如果您正在使用 Vue.js ,则方法和计算函数通常将 this 设置为 Vue 组件。
当然你可以故意使用箭头函数来覆盖这种行为,但特别是在 jQuery 和 Vue 的情况下,这通常会干扰正常运行,让你感到困惑的是为什么看起来与附近其他代码相同的代码不起作用。

总结
箭头函数是 JavaScript 语言的一个非常有必要的补充,并且在许多情况下使代码更符合人们的阅读习惯。

然而,像所有其他特性一样,它们有优点和缺点。 我们应该将它们作为我们工具箱中的另一个工具,而不是作为所有函数的全面替代品。

原文地址:https://blog.51cto.com/14623707/2472286

时间: 2024-08-29 08:43:03

JavaScript 箭头函数:适用与不适用场景的相关文章

JavaScript箭头函数中的this详解

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

Javascript 箭头函数简述

ES6 引入箭头函数有三大好处,首先,一个简洁的语法:第二,隐式return,能写成一行:第三,当你执行点击操作的语句不用在一个函数内部了. 访问ES6.io那里有大量的例子可以看一看. 对一个数据添加名称: const names = ['Wes', 'Kait','Lux']; 我们想添加Bos 到每个数组值的后面. 通常我们会这样做: const fullNames = names.map(function(name){ return `${name} Bos`; }); console.

Javascript 箭头函数2

没有参数额箭头函数 如果函数没有参数,我们可以通过()来表示,是不是有些逼格,看例子 const fullNames5 = names.map(() => `Cool Bos`); console.log(fullNames5); // Cool Bos, Cool Bos, Cool Bos 还有另一种写法就是用下划线 _ 来代替() names.map(_=>`Cool Bos`); 当然这个下划线没有任何的意义,你还可以这样做,不过这些都是没有任何含义的 names.map(x =>

JavaScript 箭头函数

1.没有参数时 var demo = function () { } //可以改写为 var demo = () => { } 2.只有一个参数时 var demo =function(arg){ } //可以改写为 var demo = arg =>{ } 3.函数体只有一条语句时 var demo = function(){ return 1 } //可以改写为 var demo =()=> return 1 注意: 当这一条语句是一个对象时 要用小括号括起来 例如 var demo

javascript 箭头函数的使用 初学者必看

为了保证可读性,本文采用意译而非直译.另外,本文版权归原作者所有,翻译仅用于学习. 本文我们介绍箭头(arrow)函数的优点. 更简洁的语法我们先来按常规语法定义函数: 1 2 3 4 5 function funcName(params) { return params + 2; } funcName(2); // 4 该函数使用箭头函数可以使用仅仅一行代码搞定! 1 2 3 var funcName = (params) => params + 2 funcName(2); // 4 是不是

javascript箭头函数

原文 https://thewebjuice.com/es6-arrows/ 1 使用es6箭头定义匿名函数 (msg)=>console.log('Hello World') es5 'use strict'; (function (msg) { return console.log('Hello World'); }); 2 单个参数和多个参数 // Multiple Parameter (arg1,arg2,arg3,arg4)=>{ return arg1+arg2+arg3+arg4

JavaScript ES6箭头函数指南

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

javascript基础修炼(8)——指向FP世界的箭头函数

一. 箭头函数 箭头函数是ES6语法中加入的新特性,而它也是许多开发者对ES6仅有的了解,每当面试里被问到关于"ES6里添加了哪些新特性?"这种问题的时候,几乎总是会拿箭头函数来应付.箭头函数,=>,没有自己的this , arguments , super , new.target ,"书写简便,没有this"在很长一段时间内涵盖了大多数开发者对于箭头函数的全部认知(当然也包括我自己),如果只是为了简化书写,把=>按照function关键字来解析就好了

JavaScript 基础(七) 箭头函数 generator Date JSON

ES6 标准新增了一种新的函数: Arrow Function(箭头函数). x => x *x 上面的箭头相当于: function (x){ return x*x; } 箭头函数相当于匿名函数,并且简化了函数定义.一种像上面的,只包含一个表达式, 连{ ... }和return都省略掉了.还有一种可以包含多条语句,这时候就不能省略{ ... }和return: x =>{ if(x > 0){ return x * x; }else{ return -x *x; } } 如果参数不是