Array.flat(数组扁平化)
Array.prototype.flat 用于把多维数组“拍平”为一维数组(或指定深度的更低维数组)。
const newArr = arr.flat(depth);
// depth 可选,默认 1
// 返回新数组,原数组不变一句话理解
flat(1):只展开一层flat(2):展开两层flat(Infinity):展开到不能再展开
行为细节(面试容易问)
1) 只会展开数组:元素是对象不会被展开。
2) 会跳过空位(holes):
[, 1, [2]].flat();
// => [1, 2]3) flat 不做“深拷贝”:
- 如果元素是对象,拍平后仍然是同一个对象引用。
手写实现思路
常见两种写法:
- 递归(直观):代码短,但深层嵌套可能导致调用栈过深
- 迭代(栈/队列):更稳,不怕递归栈
下面实现尽量贴近原生语义:
- 支持
depth,包括Infinity - 跳过 holes(不会把 holes 当
undefined放进结果) - 不建议默认覆盖
Array.prototype.flat(避免污染全局、与原生冲突)
实现 1:递归版(最常见)
export function flatRecursive<T>(arr: T[], depth: number = 1): any[] {
const result: any[] = [];
const maxDepth = depth === Infinity ? Number.POSITIVE_INFINITY : Math.max(0, depth);
const walk = (input: any[], d: number) => {
for (let i = 0; i < input.length; i++) {
if (!(i in input)) continue; // 跳过 holes
const item = input[i];
if (Array.isArray(item) && d > 0) {
walk(item, d - 1);
} else {
result.push(item);
}
}
};
walk(arr as any[], maxDepth);
return result;
}
const arr = [1, [2, 3, [4, 5]], 1, 2, [6, 7]];
flatRecursive(arr, 1); // [1,2,3,[4,5],1,2,6,7]
flatRecursive(arr, 2); // [1,2,3,4,5,1,2,6,7]实现 2:迭代版(避免递归栈)
思路:用栈保存“待处理项 + 剩余深度”,不断弹出处理。
export function flatIterative<T>(arr: T[], depth: number = 1): any[] {
const maxDepth = depth === Infinity ? Number.POSITIVE_INFINITY : Math.max(0, depth);
const stack: Array<{ value: any; depth: number }> = [];
// 从后往前入栈,保证出栈后顺序与原数组一致
for (let i = arr.length - 1; i >= 0; i--) {
if (!(i in arr)) continue; // 跳过 holes
stack.push({ value: (arr as any)[i], depth: maxDepth });
}
const result: any[] = [];
while (stack.length) {
const { value, depth: d } = stack.pop()!;
if (Array.isArray(value) && d > 0) {
for (let i = value.length - 1; i >= 0; i--) {
if (!(i in value)) continue;
stack.push({ value: value[i], depth: d - 1 });
}
} else {
result.push(value);
}
}
return result;
}复杂度
设数组中可达元素总数为 (拍平后元素数量的量级):
- 时间:
- 空间:(结果数组 + 递归/栈开销)
常见坑点
depth = 0时应该返回浅拷贝(不展开)。- 要注意 holes 行为:原生
flat会移除 holes。 - 超深嵌套建议用迭代版,避免递归调用栈溢出。