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.发布订阅&nbsp;on&nbsp;emit&nbsp;off&nbsp;once2.深拷贝&nbsp;(考虑循环引用&nbsp;set&nbsp;map&nbsp;date等等数据结构)3.防抖节流(写成&nbsp;react&nbsp;hook)4.倒计时组件5.写一个动画,把div从a点滑动到b点6.手写jsonp7.岛屿数量8.最长不重复字符9.实现并发,需要多个请求并行发送,回来的数据也是按顺序返回10.反转链表11.K个一组反转12.删除倒数第n个链表节点13.解析url为对象14.数组转树15.树转数组16.dom转json17.json转dom18.写一个搜索展示组件,要用到usetranstion&nbsp;实现输入的优先级高于渲染优先级19.爬楼梯&nbsp;及其各种变种20.序号比较21.dp常见的几道:零钱兑换&nbsp;最长财富子数据&nbsp;最长上升子序列......22.全排列23.实现一个计算器函数&nbsp;得出类似'2*8+1-3'这种计算式的答案24.高亮匹配(字节出的,唯二写不出来的算法)const&nbsp;segments=[&quot;永乐','乐年]const&nbsp;map={永':[&quot;永',,求],'乐':['乐','寤','樂,'&quot;,']'年':[年,'开,','率',秆,',季,'篁]}const&nbsp;b='廟兒梁,永樂年建平漫通衆騎極衡。倒翻衡,永果建。通川谷,平漫通衆騎,極衡。姜家梁,永樂年建平漫通衝。小山谷,永樂年建。溝谷通單騎衝。鶯窩驼,永樂年建,陡嶺口,永樂年,建通步緩。大石溝,永樂年建平漫通泉西核桃衡,永樂年建平漫通衆騎極衡。東核桃衝,永集年建衆騎極衝。寺兒梁,永樂年建平漫通衆騎極衡,火石嶺,永平漫通衆騎極衡。西凉水泉,永樂年建平漫通衆騎極衡。泉,永樂年建。水口迤西平漫通衆騎,極衡,餘通步緩。永樂年建通單騎衝。邊城三十一里,嘉靖三十四年建;b中包含segments所有可能变形字的情况,都高亮〈b&gt;&lt;'廟兒梁,〈b〉永樂年〈/b〉25.双指针判断回文(字节出的,简直弱智)26.已知异步加法函数addRemote的定义如下,该函数接收两个数字,通过异步方式返回两数之和(包含随机延迟):const&nbsp;addRemote&nbsp;=&nbsp;async&nbsp;(a,&nbsp;b)&nbsp;=&gt;&nbsp;new&nbsp;Promise(resolve&nbsp;=&gt;&nbsp;{setTimeout(()&nbsp;=&gt;&nbsp;resolve(a&nbsp;+&nbsp;b),&nbsp;Math.floor(Math.random()&nbsp;*&nbsp;400&nbsp;+&nbsp;100));});请实现本地的add方法,调用addRemote以性能最优的方式实现输入数字的加法运算。27.汉诺塔问题(抖音搜索-字节三面)28.封装一个工具函数输入promise&nbsp;如果超过1s没返回则抛出异常如果正常则输出正确的值。29.lazyMan(腾讯)30.lodash.get()31.lodash.set()32.大数相加(字符串版&nbsp;链表版)33.给一个字符串,里面有乱码的东西,把乱码的都给删掉34.数据流的中位数(wxg二面)35.合并区间36.最大子数组和37.最小覆盖字串38.写一个new反正大大小小就是这些东西,不用刷那么多奇奇怪怪的算法题把常见的这些都搞懂再说,面到不会写的,那就是缘分不到
一人分享一道面试手撕题
点赞 评论 收藏
分享
评论
6
38
分享

创作者周榜

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