JS基础(1)——数组扁平化、去重、类数组转化为数组
一、数组扁平化
const arr1 = [1, [2, [3, [4, 5]]], 6];
// => [1, 2, 3, 4, 5, 6]
1.ES6的flat()
const res1_1 = arr1.flat(Infinity);
Array.prototype.flat() 特性总结:
- 用于将嵌套的数组扁平化,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
- 不传参数时,默认扁平化一层,可以传入一个整数,表示想要扁平化的层数。
- 传入 <=0 的整数将返回原数组,不扁平化
- Infinity 关键字作为参数时,无论多少层嵌套,都会转为一维数组
- 如果原数组有空位,Array.prototype.flat() 会跳过空位。即删除空位。
局限:必须考虑兼容性
手写 flat函数
// 传入两个参数:数组arr 扁平化层数depth(默认是一层)
function flat(arr, depth = 1) {
return depth > 0 ? // 层数大于0才进行扁平化
arr.reduce((acc, cur) => { // acc:reducer 函数的返回值(累计器),cur:当前值(arr 中遍历到的当前元素值)
if(Array.isArray(cur)){ // 当前值是 数组
return [...acc, ...flat(cur, depth - 1)]; // 递归执行 flat 函数,插入返回数组中 累计器的值后面
}
return [...acc, cur]; // 当前值不是数组,直接插入返回数组中 累计器后面
}, [])
: arr; // 扁平化层数小于等于0,直接返回原数组 ar
}
2.正则
const res1_2 = JSON.stringify(arr1).replace(/(\[|\])/g, '').split(',');
const res1_3 = JSON.parse('[' + JSON.stringify(arr1).replace(/(\[|\])/g, '') + ']');
//const res1_3 = JSON.parse(`[${JSON.stringify(arr1).replace(/(\[|\])/g, '')}]`);
3.reduce()递归
const flatten = arr => {
return arr.reduce((pre,cur) => {
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
// return pre.concat(cur instanceof Array ? flatten(cur) : cur);
},[]);
// return Array.isArray(arr)
// ? arr.reduce( (acc, cur) => [...acc, ...flatten(cur)] , [])
// : [arr];
}
const res1_4 = flatten(arr1);
4.函数递归
const res1_5 = [];
const fn = arr => {
for(let i = 0; i < arr.length; i++){
Array.isArray(arr[i]) ? fn(arr[i]) : res1_5.push(arr[i]);
}
}
fn(arr1);
function flat(arr) {
let result = []
for (const item of arr) {
item instanceof Array ? result = result.concat(flat(item)) : result.push(item)
}
return result
}
const res1_5_2 = flat(arr1);
5.迭代+展开运算符
// 每次while都会合并一层的元素,这里第一次合并结果为[1, 1, 2, 1, 2, 3, [4,4,4]]
// 然后arr.some判定数组中是否存在数组,因为存在[4,4,4],继续进入第二次循环进行合并
let arr = [1, [1,2], [1,2,3,[4,4,4]]]
while (arr.some(Array.isArray)) {
arr = [].concat(...arr);
}
二、数组去重
const arr2 = [1, 1, '1', 17, true, true, false, false, 'true', 'a', [], [], {}, {}];
// => [1, '1', 17, true, false, 'true', 'a', [], [], {}, {}]
1.ES6的Set
const res2_1 = Array.from(new Set(arr2));
2.两层for+splice
const unique1 = arr =>{
let len = arr.length;
for(let i = 0; i < len; i++){
for(let j = i + 1; j < len; j ++){
if(arr[i] === arr[j]){
arr.splice(j,1);
len --;
j --;
}
}
}
return arr;
}
const res2_2 = unique1(arr2);
3.indexOf
const unique2 = arr => {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
const res = [];
for(let i = 0; i < arr.length; i++){
if(res.indexOf(arr[i]) === -1){
res. push(arr[i]);
}
}
return res;
}
const res2_3 = unique2(arr2);
4.includes
const unique3 = arr => {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
const res = [];
for(let i = 0; i < arr.length; i++){
if(!res.includes(arr[i])){
res. push(arr[i]);
}
}
return res;
}
const res2_4 = unique3(arr2);
5.hasOwnProperty
const unique7 = arr => {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
const res2_8 = unique7(arr2);
6.filter
const unique4 = arr => {
return arr.filter((item,index) => {
return arr.indexOf(item) === index;
})
}
const res2_5 = unique4(arr2);
7.ES6的map
const unique5 = arr => {
const map = new Map();
for(let i = 0; i < arr.length; i++){
if(!map.has(arr[i])){
map.set(arr[i], true);
}
}
return res;
}
const res2_6 = unique5(arr2);
8.sort()
const unique6 = arr => {
if (!Array.isArray(arr)) {
console.log('type error!');
return;
}
arr = arr.sort();
var res = [arr[0]];
for(let i = 1; i < arr.length; i++){
if(arr[i] !== arr[i-1]){
res.push(arr[i]);
}
}
return res;
}
const res2_7 = unique6(arr2);
9.对象属性不能相同
(这种数组去重的方法有问题,有待改进)
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var arrry= [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
arrry.push(arr[i])
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}] //两个true直接去掉了,NaN和{}去重
三、类数组转化为数组
类数组是具有length属性,但不具有数组原型上的方法。
常见的类数组有arguments、DOM操作方法返回的结果。
<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>
1.Array.from
const res3_1 = Array.from(document.querySelectorAll('div'));
2.Array.prototype.slice.call
原理:数组的slice()方法可以从已有数组中返回一个新数组,它可以接受两个参数arr.slice(start,end),第一个参数规定从何处开始选取,第二个参数表示从何处选取结束,如果不传参将返回原数组的一个副本,但该方法不会修改原数组,而是返回截取的新数组。
const res3_2 = Array.prototype.slice.call(document.querySelectorAll('div'));
// Array.prototype.slice.apply(document.querySelectorAll('div'))
3.扩展运算符
const res3_3 = [...document.querySelectorAll('div')];
4.Array.prototype.concat.apply
const res3_4 = Array.prototype.concat.apply([], document.querySelectorAll('div'))
// Array.prototype.concat.call([], ...document.querySelectorAll('div'))