当你需要拷贝一个数组的全部或者部分到一个新数组的时候, 优先使用 map 和 filter 而不是 forEach.
咨询工作的好处之一是我可以看到无数的项目. 这些项目在规模, 使用的编程语言和开发人员的能力方面差别很大. 虽然有很多我觉得应该废弃的模式, 但是在 JavaScript 中, 我觉得最应该废弃的是使用 forEach 创建新的数组. 事实上, 这个模式非常简单, 看起来如下所示:
- const kids = [];
- people.forEach(person => {
- if (person.age <15) {
- kids.push({ id: person.id, name: person.name });
- }
- });
上面代码做的操作就是处理包含所有人的数组, 并找出年龄小于 15 的人. 然后把每一个符合条件的'孩子'的部分属性组成的新对象添加到 kids 数组中.
虽然可以满足需求, 但是有一种势在必行的编码方式 (查看 编程范式 https://en.wikipedia.org/wiki/Programming_paradigm ). 所以, 你可能会想哪里出了问题? 要理解这一点, 让我们先熟悉两个 "朋友":map 和 filter.
map & filter
map 和 filter 是在 2015 年作为 ES6 特征集的一部分引入到 JavaScript 中的. 它们是数组的方法, 允许在 JavaScript 中使用更函数式的编码风格. 和在函数式编程的世界里一样, 这两个方法也不会修改原数组, 而是返回一个新数组. 它们都接受一个类型是函数的单一变量. 然后, 这个函数会在原数组的每一项上被调用去产生最终结果. 让我们看下这两个方法做了什么:
map: 每一项调用函数的返回结果会放在这个方法返回的新数组里.
filter: 每一项调用函数的返回结果决定这一项是否会被该方法返回的数组包含.
类似的还有一个方法, 只是很少被用到, 也就是 .
以下是查看实际操作的简单例子:
- const numbers = [1, 2, 3, 4, 5];
- const doubled = numbers.map(number => number * 2); // [2, 4, 6, 8, 10]
- const even = numbers.filter(number => number % 2 === 0); // [2, 4]
现在我们知道 map 和 filter 是干什么的了, 接下来我们会看到一个例子, 在这个例子中会展示我更偏向于怎么写前面的例子:
- const kids = people
- .filter(person => person.age <15)
- .map(person => ({ id: person.id, name: person.name }));
如果你想了解用在 map 方法里面的 lambda 表达式的语法, 查看这个 Stack Overflow 回答 https://stackoverflow.com/a/28770578/1744702 了解详情.
所以, 这种实现方式的好处如下:
关注点分离: 过滤和改变数据的格式是两个不相关的关注点, 对两个关注点分别使用各自的方法可以达到关注点分离的目的.
易于测试: 两种目的都使用了简单的 纯函数 https://en.wikipedia.org/wiki/Pure_function , 使得各种行为的单元测试变得简单. 值得一提的是最初的实现版本并不是纯粹的, 因为依赖一些作用域外边的状态 (keys 数组).
可读性: 因为这两个方法有明确的目的, 一个是过滤数据, 一个是改变数据的格式, 所以很容易看出对数据做了哪些处理. 尤其是像 reduce 这样的同类函数.
异步编程: forEach 和 async/await 不能很好地结合在一起. 但是 map 提供了一种有用的模式, 可以和 promises 和 async/await 一起使用. 更多关于这一点的内容会在下一篇博客中介绍.
同样值得注意的是, 当你想产生副作用的时候, 比如修改全局状态, 不要使用 map. 尤其是当 map 方法的返回值并不会被保存或者使用的时候.
总结
使用 map 和 filter 有很多好处, 比如关注点分离, 易于测试, 可读性和异步编程的支持. 因此, 对我来说这是一个明智的选择. 但是, 我经常遇到使用 forEach 的开发人员. 虽然函数式编程可能有点儿吓人, 但是这些方法并没有什么好害怕的, 即使它们有一些函数式编程的特征. map 和 filter 在 响应式编程 https://en.wikipedia.org/wiki/Reactive_programming 中也被大量的用到. 由于 RxJS http://reactivex.io/rxjs/ , 现在响应式编程在 JavaScript 中被越来越多的用到. 但请注意, 它们可能会永久地改变你的编码方式.
来源: http://www.jianshu.com/p/746bd2bf8f92