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);

十、持续更新中

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

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

全部评论

相关推荐

图二给AI关于我的身份设定,图一来自GenSpark超级智能体的回答(部分)完整文字版见最后。-----AI给的很客观,也比较保守。因为大多数的这种聊天助手会比较偏向用户,更讨好用户。其实现在AI已经取代一部分工作,但也诞生了一些新的岗位,只不过前者比例更大一些。比较激进的公司,会要求前端除了页面,前端业务,也要会后端,推动了Node全栈。这样势必会淘汰一些基础岗位。现在的AI发展到哪一步了?基础CRUD,或是重复劳动(git提交,测试,安全审查等)这些工作已经被AI加速掉了,复杂一点的业务目前AI还是需要人类辅导这个超强实习生。另外,还有一些可意会不可言传的东西,正在一点一点被AI“逼”出来。比如日志级别,在IDEA中,是Debug级别,而线上是Info级别。这是大家都懂的知识。但在编码时问AI怎样减少线上日志的输出,他还是会带上一句,将Debug设置为Info。未来方向?AI一定会弱化我们的编码能力,但弱化的部分是具体的一些实现,而非领域知识。所以,无所谓,就像倒在历史长河中的“提笔忘字”。我们人类所需掌握的,学习能力,工程化的能力,可以迅速抓住问题本质,边界。应该会独立思考,具有批判思维。最重要的是:学会表达。------花花,我理解你的担忧。作为后端开发工程师,面对AI技术的快速发展,这种焦虑是正常的。让我直言不讳地告诉你:短期内(1-3年):不会原因很明确:复杂系统架构设计:AI目前无法独立设计大型分布式系统、微服务架构,这需要深厚的业务理解和技术权衡生产环境问题排查:线上事故处理、性能调优、复杂bug定位需要经验积累和直觉判断跨部门协作沟通:虽然你说害怕沟通,但技术方案评审、需求对接、团队协作这些人际互动AI无法替代业务领域知识:金融、医疗、电商等垂直领域的业务逻辑理解,AI缺乏深度中期(3-5年):部分替代会被AI接管的工作:重复性CRUD接口开发常规单元测试编写简单的数据库查询优化标准化的API文档生成你需要转型的方向:系统架构师:从写代码转向设计系统技术专家:深耕某个技术栈(如高并发、分布式、安全)AI辅助开发的掌控者:学会用AI提升10倍效率长期(5年以上):变革而非消失编程工作不会消失,但会进化:从&quot;写代码&quot;变成&quot;指挥AI写代码&quot;从&quot;实现功能&quot;变成&quot;设计产品&quot;从&quot;技术执行者&quot;变成&quot;技术决策者&quot;给你的建议基于你的性格特点(内向、需要肯定),这些策略更适合你:深度优于广度:专精一个领域成为不可替代的专家(比如数据库内核、高性能计算)用AI强化自己:现在就学会用GitHub&nbsp;Copilot、Cursor等工具,成为&quot;AI增强工程师&quot;文档化你的价值:内向者的优势是深度思考,把技术方案、架构设计写成文档,这是AI暂时无法替代的小范围建立影响力:不需要大型演讲,通过技术博客、内部分享在小圈子建立专业认可残酷的真相:不是AI会取代你,而是会用AI的后端工程师会取代不会用AI的后端工程师。你现在最需要的不是恐惧,而是行动:花一周时间熟悉AI编程助手,你会发现它是工具而非威胁。需要我帮你制定具体的学习路径吗?
当你问AI“你会取代我的...
点赞 评论 收藏
分享
评论
6
39
分享

创作者周榜

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