关于数组的一些操作

146 阅读3分钟

1、数组扁平化

示例:

const arr = [1,[2,[3,[4,5]]],6];
// => [1,2,3,4,5,6]

方法1:函数递归

const arr1 = [];
const fn = arr =>{
	for(let i = 0; i < arr.length; i++){
    	// 判断是否为数组
    	if(Array.isArray(arr[i])){
        	// 是数组递归调用
        	fn(arr[i])
        } else {
        	arr1.push(arr[i])
        }
    }
}
fn(arr);

方法2:使用flat() es6方法

flat(param)方法的参数是指定要提取嵌套数组的结构深度,参数可选,默认为1,Infinity代表展开任意深度的嵌套数组

const arr2 = arr.flat(Infinity);

方法3:使用reduce()方法

语法以及使用描述

arr.reduce(function(prev,cur,index,arr){
...
}, init);
// arr 表示原数组;
// prev 表示上一次调用回调时的返回值,或者初始值 init;
// cur 表示当前正在处理的数组元素;
// index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
// init 表示初始值。
// 其实常用的参数只有两个:prev 和 cur。
const arr3 = arr =>{
	return arr.reduce((pre, cur) => {
    	return pre.concat(Array.isArray(cur) ? arr3(cur) : cur) 
    },[])
}

方法4:toString & split & map || join & split & map

cosnt arr4 = arr.toString().split(',').map((item) => {
	return Number(item)
})

const arr5 = arr.join(',').split(',').map((item) => {
	return Number(item)
})

方法5:正则表达式

const arr5 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g,'') + ']')

2、数组去重

示例:

const arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];

方法1:利用ES6 Set去重

此方法问题是 还无法去掉“{}”空对象

const arr1 = Array.from(new Set(arr)) 
// 等同于 const arr1 = [...new Set(arr)]

方法2:两层for循环 && splice去重(ES5中最常用)

此方法问题NaN和{}没有去重,两个null直接消失了

cosnt arr2 = 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]){
             	//第一个等同于第二个,splice方法删除第二个
            	arr.splice(j,1)
                len-- ; // len--, 减少循环次数,提升性能
                j--; // j--, 保证j的值经过自加后不变。
            }
        }
    }
    return arr
}
arr2(arr);

方法3:利用indexOf()方法

此方法NaN、{}没有去重

const arr3 = arr => {
	const array = [];
    for(let i = 0; i < arr.length; i++){
    	if(res.indexOf(arr[i]) === -1){
        	array.push(arr[i])
        }
    }
    return array
}
arr3(arr)

方法4:利用filter()方法

此方法{}没有去重

const arr4 = arr=>{
	return arr.filter((item, index) => {
    	//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
    	return arr.indexOf(item) === index;
    })
}
arr4(arr)

方法5:利用includes()方法

此方法{}没有去重

const arr5 = arr => {
	const arry = [];
    for(let i = 0; i < arr.length; i++){
    	ir(!arry.includes(arr[i])){
        	array.push(arr[i])
        }
    }
}
arr5(arr)

方法6:利用Map数据结构去重

此方法{}没有去重

const arr6 = arr=> {
 const map = new Map();
 const array = [];
 for(let i = 0; i < arr.length; i++){
 	if(!map.has(arr[i])){
    	map.set(arr[i], true);
        array.push(arr[i])
    }
 }
 return array
}
arr6(arr)

方法7:利用reduce+includes

此方法{}没有去重

const arr7 = arr => {
    return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
arr7(arr)

方法8:递归去重

此方法NAN,{}没有去重

const arr8 = arr => {
	const array = arr
	cosnt len = array.length;

    array.sort(function(a,b){   //排序后更加方便去重
        return a - b;
    })

    function loop(index){
        if(index >= 1){
            if(array[index] === array[index-1]){
                array.splice(index,1);
            }
            loop(index - 1);    //递归loop,然后数组去重
        }
    }
    loop(len-1);
    return array;
}
arr8(arr)

方法9:利用hasOwnProperty

此方法所有的都去重了

const arr9 = arr => {
	const obj = {};
    return arr.filter((item, index, arr) => {
    	return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
}
arr9(arr)

3、类数组转为数组

类数组是具有length属性,但不具有数组原型上的方法,常见的类数组有arguments、DOM操作方法返回的结果等

示例:

const arrDom = document.querySelectorAll('div')

方法1:Array.from()

const arr1 = Array.from(arrDom)

方法2:Array.prototype.slice.call()

const arr2 = Array.prototype.slice.call(arrDom)

方法3:利用concat()

cosnt arr3 = Array.prototype.concat.apply([],arrDom)

方法4:扩展运算符

const arr4 = [...arrDom]

4、手写filter()、map()、forEach()、reduce()方法

01、Array.prototype.filter()

Array.prototype.filter = function(callback, thisArg){
	if(this == undefined){
    	throw new TypeError('this is null or not undefined')
    }
    if(typeof callback !== 'function'){
    	throw new TypeError(callback +'is not a function')
    }
    const res = [];
    // 让obj成为回调函数的对象传递(强制转换)
    const obj = object(this);
    // >>> 0 保证len为number,且为正整数
    const len = obj.length >>> 0;
    for(let i = 0; i < len; i++){
    	// 检查i是否在obj的属性(会检查原型链)
    	if(i in obj){
        	// 回调函数调用传参
            if(callback.call(thisArg, obj[i], i, obj)){
            	res.push(obj[i])
            }
        }
    }
    return res
}

02、Array.prototype.map()

Array.prototype.map = function(callback, thisArg){
	if(this == undefined){
    	throw new TypeError('this is null or not undefined')
    }
    if(typeof callback !== 'function'){
    	throw new TypeError(callback +'is not a function')
    }
    const res = [];
    const obj = object(this);
    const len = obj.length >>> 0;
    for(let i = 0; i < len; i++){
    	if(i in obj){
        	res[i] = callback.call(thisArg, obj[i], i, this)
        }
    }
    return res
}

03、Array.prototype.forEach()

Array.prototype.forEach = function(callback, thisArg){
	if(this == undefined){
    	throw new TypeError('this is null or not undefined')
    }
    if(typeof callback !== 'function'){
    	throw new TypeError(callback +'is not a function')
    }
    const obj = object(this);
    const len = obj.length >>> 0;
    let k = 0;
    while(k < len){
    	if(k in obj){
        	callback.call(thisArg, obj[k], k, obj)
        }
        k++;
    }
}

04、Array.prototype.reduce()

Array.prototype.reduce = function(callback, initialValue){
	if(this == undefined){
    	throw new TypeError('this is null or not undefined')
    }
    if(typeof callback !== 'function'){
    	throw new TypeError(callback +'is not a function')
    }
    const obj = object(this);
    const len = obj.length >>> 0;
	let accumulator = initialValue;
    let k = 0;
    // 如果第二个参数为undefined的情况下
    // 则数组的第一个有效值作为累加器的初始值
    if(accumulator === undefined){
    	while(k < len && !(k in obj)){
        	k++;
        }
        // 如果超出数组界限还没有找到累加器的初始值,则typeError
        if(k >= len){
        	throw new TypeError('Reduce of empty array with no initial value'); 
        }
        accumulator = obj[k++];
    }
    while(k < len){
    	if(k in obj){
        	accumulator = callback.call(undefined, accumulator, obj[k], k, obj);
        }
        k++;
    }
    return accumulator;
}

5、手写call()、apply()、bind()

01、Function.prototype.call()

第一个参数是绑定的this,默认为window,第二个参数一个参数列表。

Function.prototype.call = function(context = window, ...args){
	if(typeof this !== 'function'){
    	throw new TypeError('Type Error');
    }    
    const fn = Symbol('fn');
    context[fn] = this;
    const res = context[fn](...args)
    delete context[fn];
    return res;
}

02、Function.prototype.apply()

第一个参数是绑定的this,默认为window,第二个参数是数组或类数组。

Function.prototype.apply = function(context = window, args){
	if(typeof this !== 'function'){
    	throw new TypeError('Type Error');
    }    
    const fn = Symbol('fn');
    context[fn] = this;
    const res = context[fn](...args)
    delete context[fn];
    return res;
}

03、Function.prototype.bind()

Function.prototype.bind = function(context, ...args){
	if(typeof this !== 'function'){
    	throw new TypeError('Type Error');
    }   
    // 保存this的值
    let self = this;
    return function Fn(){
    	// 考虑new的情况
        if(this instanceof Fn){
        	return new self(...args, ...arguments)
        }
        return self.apply(context, [...args, ...arguments])
    }
}