今天到flat了,一个第一次知道该方法还是看到一个面试题,别人给了个答案,用到了flat才知道的方法。
前面也写过关于这道面试题的文章,《一道关于数组的前端面试题》。
这里再来说说吧!
flat:flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
不考虑他所谓指定深度,直白一点来说,就是数组扁平化,也就是把一个有多层嵌套的数组,提取为一个只有一层的数组。
同样,先看用法吧:
var elements = ['Fire', 'Wind', 'Rain', ['apple', 'orange', [1,2,3], 'green']]; console.log(elements.flat()); console.log(elements.flat(Infinity));
前面,已经看了那么多的数组方法,基本上可以说数组方法的使用,基本上是一个套路,没什么可以刻意解释的地方。到这里可能比较关心这两个调用方法的输出结果是什么!
看出区别了吗?
其实也就是参数导致的返回结果的差别。
好吧,那我们就再来看他的语法吧!var newArray = arr.flat(depth)
flat有一个参数depth,默认为1,那这个参数究竟起到什么样的作用呢?
看他的解释,基本上就可以理解,“按照一个可指定的深度递归遍历数组”,这个参数depth也就是我们使用时所指定的深度,也就是说,我们可以指定遍历到多少层数组,提取出来扁平化。
语言描述始终有点绕口,还是用示例来说吧!var elements = ['Wind',[1,3, [4,6, [7,9, [10,[20,21],11,12]]]], 'Rain']; console.log(elements.flat()); console.log(elements.flat(2)); console.log(elements.flat(3)); console.log(elements.flat(4)); console.log(elements.flat(Infinity));
我们把参数分别设置成了默认,和2、3、4、Infinity,看一下输出结果呢?
看出什么了吗?也就是数组里面嵌套数组,一层层的嵌套的时候,通过指定depth,可以递归到那一层深度的数组,展开合并到第一层。事实上,这种用法的场景似乎并不多,基本上要不是展开所有层级的数组元素,要不就是只展开第一层的,所以参数值用的最多的应该就是Infinity,和不传参数吧!
考虑到这一点,以及递归到指定深度这种确实比较麻烦,所以我们重构该方法的时候,就只通过布尔值提供展开第一层和所有层级的选项吧!function flat (arr, depth) { if (!(arr instanceof Array)) throw new Error("请确保第一个参数类型为数组") var results = [] for (var i = 0; i < arr.length; i++) { if (!(arr[i] instanceof Array)) { results[results.length] = arr[i] } else { for (var j = 0; j < arr[i].length; j++) { if (depth && (arr[i][j] instanceof Array)) { var dees = flat(arr[i][j], depth) if (dees instanceof Array) { for (var n = 0; n < dees.length; n++) { results[results.length] = dees[n] } } } else { results[results.length] = arr[i][j] } } } } return results }
稍微解释一下,两次循环,第一次循环的是数组本身,如果当前元素类型不是数组,那直接存入到results当中,如果是数组,就再做一次循环,这一次就有点区别了,需要判断depth参数值了,如果depth为false,或者当前元素不是数组,那么依然直接存到results当中,如果depth=true,并且元素依然是数组,那就需要递归调用dees = flat(arr[i][j]),然后对dees再次循环存入results。最终返回results。
比较复杂的flat介绍完了,下面是比较常用的forEach了。forEach:forEach()
方法对数组的每个元素执行一次提供的函数。
字面理解就是相当于封装一下for循环。跟我们jQuery当中的$.each方法非常类似。
我们直接看语法吧:
arr.forEach(callback[, thisArg]);
又遇到了回调函数,与之前的一样,回调函数的参数完全一样,当前元素值,索引,数组本身。以及forEach函数另一个可选的指向this的参数。
真没啥好说的,就是在循环体内,执行一次回调函数。function forEach(arr, fn, thisArg) { if (!(arr instanceof Array)) throw new Error("请确保第一个参数类型为数组") for (var i = 0; i < arr.length; i++) { fn.call(thisArg, arr[i], i) } return arr }
好了,forEach说完了。
map: map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
一个与forEach特别像的方法,最大的区别是,map返回新的数组实例。那么就需要回调函数有返回值,利用每一个回调函数返回结果,组成新的数组实例。
用法与forEach完全一致:
var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])
直接看重构的方法吧!
function map(arr, fn, thisArg) { if (!(arr instanceof Array)) throw new Error("请确保参数类型为数组") var results = [] for (var i = 0; i < arr.length; i++) { results[i] = fn.call(thisArg, arr[i], i) } return results }
map也说完了,只能说经历了flat的洗礼,forEach和map实在是太简单了。