跳到主要内容

Array.prototype.flat()

释义

flat 作为 JavaScript 中的数组方法,可以用于扁平化多维数组。其作用是将数组中的子数组“拉平”到指定的深度,变成一维数组。

词汇解释

  • 形容词 (adj.):平的;水平的;平滑的;扁平的;枯燥的;平淡的;色彩单调的;不景气的;断然的;降音的;低于标准音高的;走了气的;电用完了的;瘪了的。
  • 名词 (n.):公寓;一套房间;单元房;平面部分;低洼地;无障碍平地赛马季节;降半音;瘪了的轮胎;平面布景。
  • 副词 (adv.):平躺地;断然;低于标准音高。
  • 动词 (vi.):合住公寓。

参数

结构深度:控制扁平化的深度。即多少层嵌套的数组会被扁平化成一维数组。

使用示例

扁平化多维数组

// Array.prototype.flat() ES2019

// 示例:扁平化二维数组
const arr = [0, 1, [2, 3], 4, 5];
// 返回一个新的数组,将二维数组拍平
const newArr = arr.flat();
console.log(newArr === arr); // false

const arr1 = [0, 1, [1, 2, [3, 4], 5], 6];
// 默认参数为1,表示浅层扁平化
const newArr1 = arr1.flat(2);
console.log(newArr1); // [0, 1, 1, 2, 3, 4, 5, 6]

处理多维数组

扁平化所有层级的数组

通过设置Infinity来扁平化至所有层级:

const arr1 = [0, 1, [1, 2, [3, 4], 5], 6];
// 使用 Infinity 实现完全扁平化
const newArr1 = arr1.flat(Infinity);
console.log(newArr1); // [0, 1, 1, 2, 3, 4, 5, 6]

负值深度

如果传入负值作为深度参数,将不会进行任何扁平化操作。

const arr1 = [0, 1, [1, 2, [3, 4], 5], 6];
// 传入负数深度值,数组不做扁平化处理
const newArr1 = arr1.flat(-2);
console.log(newArr1); // [0, 1, [1, 2, [3, 4], 5], 6]

字符串作为深度

传入字符串会被视为 NaN,因此不会进行任何扁平化操作。

const arr1 = [0, 1, [1, 2, [3, 4], 5], 6];
// 传入字符串 'a',将无法进行扁平化处理
const newArr1 = arr1.flat('a');
console.log(newArr1); // [0, 1, [1, 2, [3, 4], 5], 6]

数字字符串作为深度

数字字符串会被转换为 NaN,因此不会执行扁平化操作。

const arr1 = [0, 1, [1, 2, [3, 4], 5], 6];
// 传入数字字符串 '3',该值转换为 NaN,不会进行扁平化
const newArr1 = arr1.flat('3');
console.log(newArr1); // [0, 1, [1, 2, [3, 4], 5], 6]

布尔值作为深度

布尔值 false 等同于 0,true 等同于 1。因此可以根据布尔值控制扁平化的层数。

const arr1 = [0, 1, [1, 2, [3, 4], 5], 6];
// false 等同于 0,不做任何扁平化
const newArr1 = arr1.flat(false);
console.log(newArr1); // [0, 1, [1, 2, [3, 4], 5], 6]

// true 等同于 1,执行一层扁平化
const newArr2 = arr1.flat(true);
console.log(newArr2); // [0, 1, 1, 2, [3, 4], 5, 6]

处理稀疏数组

flat 方法会自动剔除 empty(稀疏数组中的空位)。

const arr1 = [1, , , , 2, , , 3, , 4, [2, [3], 2], 2, 32];
// 扁平化至所有层级,剔除空位
const newArr1 = arr1.flat(Infinity);
console.log(newArr1); // [1, 2, 3, 4, 2, 3, 2, 2, 32]

扁平化方法实现

浅扁平化

浅扁平化只会展开一层嵌套数组,常见的实现方式是使用 reduceconcat

// 通过 reduce + concat 实现浅扁平化
function shallowFlat(arr) {
return arr.reduce(function (prev, current) {
return prev.concat(current);
}, []);
}

// 使用扩展运算符实现简化版本
function shallowFlat(arr) {
return [].concat(...arr);
}

深度扁平化

使用 reduce + isArray + concat + 递归

递归处理每一层嵌套,直到达到指定的深度。

Array.prototype.deepFlat = function () {
var arr = this,
deep = arguments[0] !== Infinity ? arguments[0] >>> 0 : Infinity;

return deep > 0
? arr.reduce(function (prev, current) {
return prev.concat(Array.isArray(current) ? current.deepFlat(deep - 1) : current);
}, [])
: arr;
};

const arr1 = [1, , , , 2, , , 3, , 4, [2, [3], 2], 2, 32];
console.log(arr1.deepFlat(Infinity)); // [1, 2, 3, 4, 2, 3, 2, 2, 32]

使用 forEach + isArray + push + 递归

通过 forEach 遍历数组,递归调用处理每一层的嵌套。

Array.prototype.deepFlat = function () {
var arr = this,
deep = arguments[0] !== Infinity ? arguments[0] >>> 0 : Infinity,
res = [];

(function _(arr, deep) {
arr.forEach(function (item) {
if (Array.isArray(item) && deep > 0) {
_(item, deep - 1);
} else {
res.push(item);
}
});
})(arr, deep);

return res;
};

使用 for of + isArray + push + 递归

通过 for of 循环遍历每个元素,判断是否为数组并递归处理。

Array.prototype.deepFlat = function () {
var arr = this,
deep = arguments[0] !== Infinity ? arguments[0] >>> 0 : Infinity,
res = [];

(function _(arr, deep) {
for (var item of arr) {
if (Array.isArray(item) && deep > 0) {
_(item, deep - 1);
} else {
item !== void 0 && res.push(item); // 剔除空位
}
}
})(arr, deep);

return res;
};

使用栈(stack)+ pop + push

通过栈的方式,逐步展开数组。

Array.prototype.deepFlat = function () {
var arr = this,
stack = [...arr],
res = [];

while (stack.length) {
const popItem = stack.pop();

if (Array.isArray(popItem)) {
stack.push(...popItem);
} else {
if (popItem != undefined) {
res.push(popItem);
}
}
}

return res.reverse();
};

const arr1