js手撕大全

一、数组扁平化⭐⭐⭐⭐⭐

比如一数组:let arr1=[[[[[[1],2],3],4],5],6]

方法一:flat

arr1.flat(Infinity)

方法二:递归

function flat1(arr){
    let newArr =[];
    arr.forEach(i=>{
        if(Array.isArray(i))
        {newArr=newArr.concat(flat2(i))}
        else{
            newArr.push(i)
        }
    })
    return newArr
}

方法三:遍历

function flat1(arr){
    while(arr.some(i => Array.isArray(i))){
        arr=[].concat(...arr)
    }
    return arr
}

二、对象扁平化⭐⭐⭐

  1. prefix:定位递归深度
  2. res:把扁平化的对象放入
  3. hasOwnProperty:只处理 obj 自有属性,防止遍历到原型链上其他的键
  4. value和newkey:获取值和当前完整的键
  5. 数组判断:引入[]
  6. 对象判断:递归

function flatObj(obj,prefix='',res={}){
    for(let key in obj){
        if(Object.prototype.hasOwnProperty.call(obj, key)){
            const value = obj[key];
            const newkey = prefix?`${prefix}.${key}`:key;
            if(Array.isArray(value)){
                value.forEach((item,index)=>{
                    if(typeof item === 'object' && item !==null){
                        flatObj(item,`${newkey}[${index}]`,res)
                    }else{
                        res[`${newkey}[${index}]`]=item
                    }
                })
            }else if(typeof value === 'object'&&value!==null){
                flatObj(value,newkey,res);
            }else{
                res[newkey]=value;
            }


        }
    }
    return res;
}

三、数组去重⭐⭐⭐⭐⭐

let arr = [1, 2, 3, 2, 4, 1, 5];

方法一:set

result = [...new Set(arr)]

方法二:使用 filter() + indexOf()

  • filter用来过滤
  • indexOf会得到第一个的索引,
  • 通过判断当前索引是不是当前值的第一个索引来进行过滤
let result = arr.filter((item,index)=>arr.indexOf(item) ===index)

方法三:使用reduce()+inclueds()

  • reduce():设置acc=[].然后cur来遍历整个数组
  • includes():如果没有重复就push到acc
let result2 = arr.reduce((acc,cur)=>{
if(!acc.includes(cur))
{acc.push(cur)}
return acc
},[])

四、对象数组的去重⭐⭐

let users = [ { id: 1, name: "Tom" }, { id: 2, name: "Jerry" }, { id: 1, name: "Tom" }, { id: 3, name: "Spike" } ];

方法一:Map()+reduce()

  • reduce():设置acc为{map:new Map(),results:[]},
  • 然后每次利用map的has和set方法来判断是否重复
  • 如果不重复就push到数组acc.resultws
let results = users.reduce(
    (acc,cur) =>{
        if(!acc.map.has(cur.id)){
            acc.map.set(cur.id,true);
            acc.results.push(cur)
        }
        return acc
    }
    , {map: new Map(),results:[]}
).results

方法二:Set()+reduce()

  • reduce():设置acc为[]。然后对比cur.id存在不存在,不存在就push到acc里面
  • Set():Set() 在这里主要用作快速判断重复,与 Map() 的键记录重复的思路类似,但更简洁。
let set1 = new Set()
let results2 = users.reduce((acc,cur)=>{
    if(!set1.has(cur.id)){
        set1.add(cur.id);
        acc.push(cur)

    }
    return acc
},[])

五、手撕数组的filter()方法⭐⭐

  • 传入arguments:callback和thisArg
  • 判断callback是不是null,是就throw new TypeError('it is null')
  • 判断callback是不是function,不是就throw new TypeError('is is not a function')
  • 获取obj:const obj =Object(this)
  • 获取正确长度:const len = obj.length >>>0;
  • 建立返回的数组:const arr =[]\
  • 定义thisArg,通过判定arguments.length是否大于1,来判断是否给thisArg赋值undefiend;
  • 遍历obj的索引k,然后通过if(k in obj)去除空洞
  • callback(thisArg,obj[k],k,obj)是否为ture
  • 判断是否把obj[k]进一步push到arr里面
  • 返回arr
Array.prototype.myFilter = function(callback,thisArg){
    if(this == null){
        throw new TypeError('it is null or undefined')
    }
    if(typeof callback !== 'function'){
        throw new TypeError(callback + 'is not a function');
    }
    const obj = Object(this)//把this指向arr.myFilter中的arr
    const len = obj.length >>>0;//>>>0是为了1.转换为数字2.去掉小数3.去掉负数符号
    const arr =[]; //返回的新数组
    thisArg = arguments.length>1?arguments[1]:undefined;//这里arguments指定function里面的参数个数
    for(let k = 0;k<len;k++){
        if(k in obj){//k in obj 是为了跳过空洞
            const value = obj[k];
            if(callback.call(thisArg,value,k,obj)){
                arr.push(value)
            }
        }
    }
    return arr;

}
const numbers = [1, 2, 3, 4];
const even = numbers.myFilter(x => x % 2 === 0);
console.log(even); // [2,4]

六、手撕数组的map()方法⭐⭐

  • 传入arguments:callback和thisArg
  • 判断callback是不是null,是就throw new TypeError('it is null')
  • 判断callback是不是function,不是就throw new TypeError('is is not a function')
  • 获取obj:const obj =Object(this)
  • 获取正确长度:const len = obj.length >>>0;
  • 建立返回的数组:const arr =[]\
  • 定义thisArg,通过判定arguments.length是否大于1,来判断是否给thisArg赋值undefiend;
  • 遍历obj的索引k,然后通过if(k in obj)去除空洞
  • callback(thisArg,obj[k],k,obj)的值直接赋值给arr[k]
  • 返回arr
Array.prototype.myMap =function (callback,thisArgs){
    if(callback == null){ throw new TypeError('it is null or undefined')}
    if(typeof callback !=='function') {throw new TypeError('it is not a function')}
    const obj = Object(this);
    const len = obj.length >>>0;
    const arr =[];
    thisArgs = arguments.length>1?arguments[1]:null;
    for(let i = 0;i<len;i++){
        if(i in obj){
            arr[i] = callback.call(thisArgs,obj[i],i,obj)
        }
    }
    return arr;
}
let numbers=[1, 2, 3, 4];
console.log(numbers.myMap((numbers)=>{return numbers*2}))

七、深拷贝手撕⭐⭐⭐⭐⭐

  1. arguments传入为obj和map = new WeakMap
  2. 判断是不是基本类型或者null
  3. 判断是不是日期
  4. 判断是不是正则
  5. 判断是不是数组
  6. 判断是不是重复
  7. 存入哈希map
  8. 遍历obj
  9. 判断是不是私有属性
  10. 执行回调
  11. 返回
function deep(obj,map = new WeakMap){
    if(typeof obj !=='object' || obj ===null) return obj;
    if(obj instanceof Date) return new Date(obj);
    if(obj instanceof RegExp) return new RegExp(obj);
    if (map.has(obj)) return map.get(obj);
    let newObj = Array.isArray(obj)?[]:{};
    map.set(obj,newObj);
    for (let key in obj){
        if(Object.prototype.hasOwnProperty.call(obj,key)){
            newObj[key]=deep(obj[key],map);
        }
    }
    return newObj;

}

八、手撕节流和防抖⭐⭐⭐⭐⭐

防抖:

  1. 搜索框输入建议(等用户停止输入后才发送请求)
  2. 表单验证(用户输入完毕后再验证)
  3. 窗口调整大小时的重新计算
  4. 避免按钮重复点击提交
  5. 即时保存文章草稿
function debounce(func,wait){
    let timeout;
    return function(...args){
        clearTimeout(timeout);
        timeout = setTimeout(()=> func.apply(this,args),wait);

    }
}

节流:

  • 滚动事件处理(如滚动加载、固定导航栏)
  • 监听resize事件调整布局
  • 拖拽操作更新界面
  • 频繁的数据请求或API调用
  • 实时游戏中的按键响应
  • Canvas 绘图操作
function throttle(func,wait){
    let last = 0;
    return function(...args){
        const now = new Date.now();
        if(now-last>wait){
            func.apply(this,args);
            last = now;
        }
    }
}

九、寄生组合式继承⭐⭐⭐⭐

  • 用this.形式定义实例属性
  • 用prototype来定义实例方法
  • 用call或者apply来继承父类的实例属性
  • 用son.prototype = Object,create(father.prototype)继承方法
  • 在用son.prototype.constructor = son修正构造函数指向
//a.父类构造函数
function Father(name){
    this.name = name;//实例属性,接受参数name
    this.friends = ['jone','tom'];//实例属性,默认属性
};
//原型方法:所有的爸爸father共享的方法
Father.prototype.hello = function(){
    console.log(`hello,i am ${this.name}`)//当前实例的name
};
//b.子类构造函数
function Son(name,age){
    Father.call(this,name);//调用父构造函数,继承实例属性
    this.age = age;//子类构造函数自己的实例
};
//c.原型链继承
Son.prototype = Object.create(Father.prototype);//继承父类源方法
Son.prototype.constructor = Son;//修正构造函数指向
//d.验证
let son = new Son('jojo',22);
son.hello();
console.log(son);
console.log(son.age);
console.log(son.friends);

十、持续更新中

#第一次找实习,我建议__#
前端面试笔记 文章被收录于专栏

双非本前端求职笔记,八股文项

全部评论

相关推荐

评论
1
5
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务