前端百题——居然有五种方式实现flat方法

1 背景

不知道老铁们有没有遇到过一道面试题:如何将一个多维数组展开成一个一维数组?当时我遇到的时候还不了解flat这个神奇的方法,用了最传统的解决方法进行解决。javascript

const flatten = arr => arr.toString().split(',').map(item => +item);

const arr = [1, 2, [3, 4, [5, 6]]];
console.log(flatten(arr)); // [ 1, 2, 3, 4, 5, 6 ]
复制代码

上述方法是否是很神奇,会将多层级的数组展开成为一个层级,可是该方式其实存在很大问题的,下面让咱们一块儿看看这些问题。html

  1. 无论多少层级都会展开为一个层级;
  2. 处理后的结果其实都是字符串,须要后续再转换为原来的类型。

正是基于这个契机,发现了ES6新增了flat函数,这个函数天生就是为数据扁平化处理而生的。java

2 flat基础

flat() 方法会按照一个可指定的深度递归遍历数组,并将全部元素与遍历到的子数组中的元素合并为一个新数组返回。git

  1. flat方法的用法以下所示:
const newArray = arr.flat([depth])
复制代码
  1. 小试牛刀
const arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat(1)); // [ 1, 2, 3, 4, [ 5, 6 ] ]
console.log(arr.flat(2)); // [ 1, 2, 3, 4, 5, 6 ]
复制代码

3 实现

flat这么香,那么咱们是否能够本身实现一个呢?实现该方法的方式有不少,下面就让咱们一块儿看看这五种方式。(注:这五种方式试MDN上给出的替代方案)github

3.1 使用reduce和concat

该方式实现起来虽然很简单,可是存在一个很大的缺陷:只能展开一层,对于多层的状况将无能为力。其思想总结起来为如下两个步骤:面试

  1. 利用reduce函数去依次处理每一个数组中的元素;
  2. 利用concat将当前的数组元素(值或子数组)添加到结果数组中。
// 使用reduce和concat
Array.prototype.flat1 = function () {
    return this.reduce((acc, val) => acc.concat(val), []);
}
复制代码

3.2 使用reduce + concat + isArray + recursivity

该方式已经具有展开多层的能力了,其实现思想可总结为如下几点:数组

  1. 利用reduce函数去依次处理每一个数组中的元素;
  2. 利用concat将当前元素添加到结果数组中;
  3. 利用isArray判断当前数组中的元素是否是一个数组;
  4. 利用递归思想展开多层级的数组。
// 使用reduce + concat + isArray +recursivity
Array.prototype.flat2 = function (deep = 1) {
    const flatDeep = (arr, deep = 1) => {
        return deep > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, deep - 1) : val), []) : arr.slice();
    }

    return flatDeep(this, deep);
}
复制代码

3.3 使用forEach + concat + isArray +recursivity

该方式与上述方式很相似,可以设定层级展开,只是遍历数组由reduce转换为forEach。函数

// 使用forEach + concat + isArray +recursivity
// forEach 遍历数组会自动跳过空元素
Array.prototype.flat3 = function (deep = 1) {
    const result = [];
    (function flat(arr, deep) {
        arr.forEach((item) => {
            if (Array.isArray(item) && deep > 0) {
                flat(item, deep - 1);
            } else {
                result.push(item);
            }
        })
    })(this, deep);

    return result;
}
复制代码

3.4 使用for of + concat + isArray +recursivity

该方式与上述方式很相似,可以设定层级展开,只是遍历数组利用了for of方法post

// 使用for of + concat + isArray +recursivity
// for of 遍历数组会自动跳过空元素
Array.prototype.flat4 = function (deep = 1) {
    const result = [];
    (function flat(arr, deep) {
        for(let item of arr) {
            if (Array.isArray(item) && deep > 0) {
                flat(item, deep - 1);
            } else {
                // 去除空元素,由于void 表达式返回的都是undefined,不适用undefined是由于undefined在局部变量会被重写
                item !== void 0 && result.push(item);
            }
        }
    })(this, deep);

    return result;
}
复制代码

3.5 使用堆栈stack

该方式主要利用堆栈的思想,将一个多层数组所有展开为一层。其思想可总结为如下几个步骤:this

  1. 将要处理的数组放到一个栈中处理;
  2. 从栈顶取出元素,判断该元素类型,若为数组,则将该数组展开再放回栈顶;若为普通元素则将其放到结果中;
  3. 循环遍历,至到栈为空。
// 使用堆栈stack
Array.prototype.flat5 = function() {
    const stack = [...this];
    const result = [];
    while (stack.length > 0) {
        const next = stack.pop();
        if (Array.isArray(next)) {
            stack.push(...next);
        } else {
            result.push(next);
        }
    }

    // 反转恢复原来顺序
    return result.reverse();
}
复制代码

1.若是以为这篇文章还不错,来个分享、点赞吧,让更多的人也看到

若是你以为这篇文章对你有点用的话,麻烦请给咱们的开源项目点点star:        http://github.crmeb.net/u/defu         不胜感激 !
来自 “开源世界 ” ,连接:      https://ym.baisou.ltd/post/737.html ,如需转载,请注明出处,不然将追究法律责任。 ​​​​​​
相关文章
相关标签/搜索