面试中常常会遇到一道扁平化数组的题目:写一个函数,将输入数组 [1, [2, [3, [4]], 5]]
转化为 [1, 2, 3, 4, 5]
的形式。面试
一开始,我觉得是经过此题来考察递归的使用,后来仔细一想,事情远远不止这么简单,本文试着经过几种方式的实现,来理解此题可能要考察的内容。数组
递归是首选思路,通常人都会想到这个方法,但若是此题只是考察递归的话,是不会这么出题的。函数
function flatten (arr) { var result = []; (function(arr) { var self = arguments.callee; arr.forEach(function(item) { // Array.isArray(item) if(item instanceof Array) { self(item); } else { result.push(item); } }); })(arr); return result; }
主要考察数组toString()
、valueOf()
方法的使用,这种状况只适合数组元素类型为String和Number,其余状况都会转换为String类型this
// 借用数组的toString方法 function flatten (arr) { var str = arr.toString(); return str.split(','); } // 借用数组的valueOf方法 Array.prototype.valueOf = function() { return this.join(',') }; function flatten2 (arr) { var str = arr.valueOf(); return str.split(','); }
考察ES6中Generator函数的使用,以及返回值做为一个遍历器对象的使用,以及数组...(扩展运算符)的使用。prototype
function *_flatten (arr) { for(let i = 0; i < arr.length; i++) { const item = arr[i]; if(Array.isArray(item)) { yield *_flatten(item); } else { yield item; } } } const flatten = arr => [..._flatten(arr)];
考察ES6中Symbol.iterator的使用code
Array.prototype[Symbol.iterator] = function () { let arr = [].concat(this); let first = function (arr) { return arr.shift(); }; return { next: function() { let item = first(arr); if (item) { return { value: item.toString(), done: false } } else { return { done: true } } } }; } const flatten = arr => { let res = []; for(let i of arr) { res.push(i); } return res.join(',').split(','); };
或者经过generator函数+递归实现htm
Array.prototype[Symbol.iterator] = function* (array) { let arr = array || this; let sel = arguments.callee; for(let i = 0; i < arr.length; i++) { const item = arr[i]; if(Array.isArray(item)) { yield *sel(item); } else { yield item; } } } // test var arr = [1, [2, [3, [4]], '5']]; console.log([...arr]);
function flatten(arr) { var arr; while (arr.some(v => Array.isArray(v))) { arr = [].concat(...arr); } return arr; }
flat()
是ES6中新增的数组方法,该方法返回一个新数组,对原数据没有影响。对象
[1, [2, [3, [4]], 5]].flat(Infinity);
参考:面试题之-扁平化数组递归