面試中常常會遇到一道扁平化數組的題目:寫一個函數,將輸入數組 [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);
參考:面試題之-扁平化數組遞歸