数组扁平化时concat可用push失效,求原因及[circular object Array]含义
问题场景
以下代码可正常实现深度嵌套数组的扁平化:
const arr = [[2, [4, 9]], 6, [5,32]]; const finalArr = []; function flattenArr(currArr) { for (var el of currArr) { if (Array.isArray(el)) { finalArr.concat(flattenArr(el)); } else { finalArr.push(el); } } return finalArr; } flattenArr(arr); console.log(finalArr); // Output:[2, 4, 9, 6, 5, 32]
但将代码中的concat替换为push后,程序运行异常,输出结果为:
[2, 4, 9, [circular object Array], [circular object Array], 6, 5, 32, [circular object Array]]
一、替换push后异常的原因
先拆解原代码逻辑:原代码里的finalArr.concat(flattenArr(el))其实是无效操作——concat方法的特性是返回新数组,不会修改原数组,你既没把返回的新数组赋值给变量,也没用到它,所以原代码的扁平化效果完全依赖递归中的push:每次遇到嵌套数组,递归调用flattenArr(el),这个递归过程会把嵌套数组里的元素逐个push到全局的finalArr中,最后函数返回finalArr本身。
当你把concat换成push后,代码变成finalArr.push(flattenArr(el)),这里flattenArr(el)的返回值就是finalArr自己(函数最后return的是finalArr),相当于你把finalArr自身作为元素push进了finalArr内部。比如第一次处理嵌套数组[2, [4,9]]时,递归结束后返回的是已经包含2、4、9的finalArr,此时执行push就会把整个finalArr塞进去,直接造成数组引用自身的循环问题,同时也多了不必要的元素,导致输出异常。
二、[circular object Array]的含义
这是浏览器控制台用来标记循环引用的特殊标识。当一个数组(或对象)直接/间接引用了自身时(比如这里finalArr被push进了自己内部),控制台无法无限递归展示这个嵌套结构,就会用[circular object Array]来标注这个位置,明确告知你此处存在数组引用自身的循环问题。
内容的提问来源于stack exchange,提问作者johnnash

