# JavaScript数据扁平化详解

## 什么是扁平化

 123 `var` `arr = [1, [2, [3, 4]]];``console.log(flatten(arr)) ``// [1, 2, 3, 4]``循环数组+递归`

 12345678910111213 `function` `flatten(arr){``     ``var` `result = [];``     ``for``(``var` `i = 0, len = arr.length; i < len; i++){``         ``if``(Array.isArray(arr[i])){``             ``result = result.concat(flatten(arr[i]));``         ``}``else``{``             ``result.push(arr[i]);``         ``}``     ``}``     ``return` `result;`` ``}`` ` `flatten(arr)   ``// [1,2,3,4]`

## 递归

 1234567891011121314151617 `   ``var` `arr = [1, [2, [3, 4]]];``     ` `    ``function` `flatten(arr) {``        ``var` `result = [];``        ``for` `(``var` `i = 0, len = arr.length; i < len; i++) {``            ``if` `(Array.isArray(arr[i])) {``                ``result = result.concat(flatten(arr[i]))``            ``}``            ``else` `{``                ``result.push(arr[i])``            ``}``        ``}``        ``return` `result;``    ``}`` ` ` ` `console.log(flatten(arr))`

## tostring

[1, [2, [3, 4]]].toString() // “1,2,3,4”``` ```

 12345678910 `// 方法2``var` `arr = [1, [2, [3, 4]]];`` ` `function` `flatten(arr) {``    ``return` `arr.toString().split(``','``).map(``function``(item){``        ``return` `+item``    ``})``}`` ` `console.log(flatten(arr))`

## reduce

 12345678910 `// 方法3``var` `arr = [1, [2, [3, 4]]];`` ` `function` `flatten(arr) {``    ``return` `arr.reduce(``function``(prev, next){``        ``return` `prev.concat(Array.isArray(next) ? flatten(next) : next)``    ``}, [])``}`` ` `console.log(flatten(arr))`
ES6 增加了扩展运算符，用于取出参数对象的所有可遍历属性，拷贝到当前对象之中：

var arr = [1, [2, [3, 4]]];
console.log([].concat(…arr)); // [1, 2, [3, 4]]

 123456789101112 `var` `arr = [1, [2, [3, 4]]];`` ` `    ``function` `flatten(arr) {``     ` `        ``while` `(arr.some(item => Array.isArray(item))) {``            ``arr = [].concat(...arr);``        ``}``     ` `        ``return` `arr;``    ``}``     ` `    ``console.log(flatten(arr))`

## undercore

 1234567 `/**`` ``* 数组扁平化`` ``* @param  {Array} input   要处理的数组`` ``* @param  {boolean} shallow 是否只扁平一层`` ``* @param  {boolean} strict  是否严格处理元素，下面有解释`` ``* @param  {Array} output  这是为了方便递归而传递的参数`` ``*/`

 12345678910111213141516171819202122232425262728293031 `    ``function flatten(input, shallow, strict, output) {` `    ``// 递归使用的时候会用到output``    ``output = output || [];``    ``var idx = output.length;` `    ``for` `(var i = 0, len = input.length; i < len; i++) {` `        ``var value = input[i];``        ``// 如果是数组，就进行处理``        ``if` `(Array.isArray(value)) {``            ``// 如果是只扁平一层，遍历该数组，依此填入 output``            ``if` `(shallow) {``                ``var j = 0, len = value.length;``                ``while` `(j < len) output[idx++] = value[j++];``            ``}``            ``// 如果是全部扁平就递归，传入已经处理的 output，递归中接着处理 output``            ``else` `{``                ``flatten(value, shallow, strict, output);``                ``idx = output.length;``            ``}``        ``}``        ``// 不是数组，根据 strict 的值判断是跳过不处理还是放入 output``        ``else` `if` `(!strict){``            ``output[idx++] = value;``        ``}``    ``}` `    ``return` `output;` `}`

var arr = [1, 2, [3, 4]];
console.log(flatten(arr, true, true)); // [3, 4]

`shallow true + strict false` ：正常扁平一层

`shallow false + strict false` ：正常扁平所有层

`shallow true + strict true` ：去掉非数组元素

`shallow false + strict true `： 返回一个[]

## _.flatten

 123 `_.flatten = ``function``(array, shallow) {``    ``return` `flatten(array, shallow, ``false``);``};`

## _.union

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

_.union([1, 2, 3], [101, 2, 1, 10], 4, 5);
=> [1, 2, 3, 101, 10]

 1234567 `function` `unique(array) {``   ``return` `Array.from(``new` `Set(array));``}`` ` `_.union = ``function``() {``    ``return` `unique(flatten(arguments, ``true``, ``true``));``}`

## _.difference

_.difference(array, *others)

_.difference([1, 2, 3, 4, 5], [5, 2, 10], [4], 3);
=> [1, 3]

 12345678 `function` `difference(array, ...rest) {`` ` `    ``rest = flatten(rest, ``true``, ``true``);`` ` `    ``return` `array.filter(``function``(item){``        ``return` `rest.indexOf(item) === -1;``    ``})``}`