不要用 arr.map 代替 arr.forEach
也是一个 JavaScript 初学者常常犯的错误,他们往往并没有分清 Array.prototype.map
和 Array.prototype.forEach
的实际含义。
map
中文叫做 映射
,它通过将某个序列依次执行某个函数导出另一个新的序列。这个函数通常是不含副作用的,更不会修改原始的数组(所谓纯函数)。
forEach
就没有那么多说法,它就是简单的把数组中所有项都用某个函数处理一遍。由于 forEach
没有返回值(返回 undefined),所以它的回调函数通常是包含副作用的,否则这个 forEach
写了毫无意义。
确实 map
比 forEach
更加强大,但是 map
会创建一个新的数组,占用内存。如果你不用 map
的返回值,那你就应当使用 forEach
补:心得补充
ES6 以前,遍历数组主要就是两种方法:手写循环用下标迭代,使用 Array.prototype.forEach
。前者万能,效率最高,可就是写起来比较繁琐——它不能直接获取到数组中的值。
笔者个人是喜欢后者的:可以直接获取到迭代的下标和值,而且函数式风格(注意 FP 注重的是不可变数据结构,forEach 天生为副作用存在,所以只有 FP 的形而没有神)写起来爽快无比。但是!不知各位同学注意过没有:forEach 一旦开始就停不下来了。。。
forEach 接受一个回调函数,你可以提前 return
,相当于手写循环中的 continue
。但是你不能 break
——因为回调函数中没有循环让你去 break
:
[1, 2, 3, 4, 5].forEach(x => { console.log(x); if (x === 3) { break; // SyntaxError: Illegal break statement } });
解决方案还是有的。其他函数式编程语言例如 scala
就遇到了类似问题,它提供了一个函数
break,作用是抛出一个异常。
我们可以仿照这样的做法,来实现 arr.forEach
的 break
:
try { [1, 2, 3, 4, 5].forEach(x => { console.log(x); if (x === 3) { throw 'break'; } }); } catch (e) { if (e !== 'break') throw e; // 不要勿吞异常。。。 }
还有其他方法,比如用 Array.prototype.some
代替 Array.prototype.forEach
。
考虑 Array.prototype.some 的特性,当 some
找到一个符合条件的值(回调函数返回 true
)时会立即终止循环,利用这样的特性可以模拟 break
:
[1, 2, 3, 4, 5].some(x => { console.log(x); if (x === 3) { return true; // break } // return undefined; 相当于 false });
内容版权声明:除非注明,否则皆为本站原创文章。