思考题 嵌套数组打平
9 Mar 2017

jansesun原创,转载请注明出处

之前在UESTC前端群里跟一些朋友分享了一些javascript的思考题,旨在促进群内技术讨论,共同进步。期间不乏思维的火花,一直想将这些宝贵的财富沉淀下来,以便日后翻阅。

这段时间有些懈怠了,很久没有更新博客,最近一个学弟在面试过程中遇到一个问题,将一个嵌套数组打平为一维数组。

嵌套数组示例为[1, 2, [5, 8, [4]], 3, 1]

常规思路是递归打平

function flattenArray(arr) {
	let result = [];
	let _flattenArray = function(arr) {
		let i, len;
		for(i = 0, len = arr.length; i < len; ++i) {
			if(Array.isArray(arr[i])) {
				_flattenArray(arr[i]);
			} else {
				result.push(arr[i]);
			}
		}
	};
	_flattenArray(arr);
	return result;
}

上面的写法中规中矩,没有问题。我是一个喜欢不走寻常路的怪咖,我苦思冥想javascript的缔造者有没有给我们提供一些不为人知的小路呢?

我发现Array.prototype.toString 我们示例数组会输出'1,2,5,8,4,3,1'

我经过进一步尝试发现以下几种方式都有异曲同工之妙。

arr.toString();
arr + '';
String(arr);
arr.join();

究其本质,后面三种都是隐式调用了数组原型方法toString,所以只要能够让javascript隐式调用toString方法就可以得到一个与数组嵌套层次无关的字符串。

看到这个字符串,有朋友可能会立即想到String.prototype.split就可以大功告成。

...当接近终点时,请冷静下...

原始数组所有元素都是Number类型,split之后会变成字符串,和我们的预期有些差异。当然再map一遍将其逐一转化为Number是可以的。不过是否有更简洁的写法呢?

如果有'[1,2,5,8,4,3,1]'这样一个字符串,我们就可以直接通过JSON.parse直接获得元素为Number的一维数组了。

function flattenArray(arr) {
	return JSON.parse(`[${arr}]`);
}

这个简洁的答案足够酷炫,不过有一定的适用范围,仅适用所有元素均为Number类型的嵌套数组打平,对于普适情况还是常规的递归打平比较靠谱,面对一些比较特殊的情形,会有一些比较简洁的思路。

希望读者能够从本文受到一些启发,那我将不甚荣幸。