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])
}
}