前端手写题-防抖、节流,深浅拷贝等



防抖

  • 声明定时器
  • 返回函数
  • 判断是否有定时器,如果有,销毁定时器
  • 创建定时器,执行函数
js 复制代码
function debounce(fn,t){
    let timer    //声明定时器
    return function(){
        let context=this   //保存上下文
        let args=arguments  //保存参数
        if(timer){
        clearTimeout(timer)}  //如果有定时器,清除定时器
        timer=setTimeout(()=>{
            fn.apply(context,args)  //执行函数
            },t)
        }
  }

节流

  • 声明定时器变量为空
  • 返回函数
  • 判断如果没有定时器,声明定时器,执行函数
  • 销毁定时器
js 复制代码
function throttle(fn,t){
    let timer=null
    return function(){
        let context=this
        let args=arguments
        if(!timer){
            timer=setTimeout(()=>{
                fn.apply(context,args)
                timer=null
            },t)
        }
    }
}

浅拷⻉

js 复制代码
//数组的浅拷贝
let ar=[1,2,3]
let br=ar.concat()
let cr=ar.slice()
let dr=[...ar]

console.log(br,cr,dr)
js 复制代码
//对象的浅拷贝
const obj={
    name:"zhangsan "
}
const newobj={...obj}
const newobj2=Object.assign(obj)
console.log(newobj,newobj2)
  • 先判断要拷贝的对象,是不是对象类型,不是的话,直接返回
  • 新建一个对象或者数组 用来结果返回
  • 然后遍历对象的可枚举属性
  • 将老对象赋值给新对象
  • 返回新对象
js 复制代码
function shallowcopy(obj) {
    // 如果不是对象,直接返回
    if (typeof obj!== 'object' || obj === null) {
        return obj;
    }
    // 判断是数组还是对象,创建相应的新对象
    let newobj = Array.isArray(obj)? [] : {};
    // 遍历对象的所有可枚举属性
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            // 复制属性值
            newobj[key] = obj[key];
        }
    }
    return newobj;
}

深拷贝

js 复制代码
const obj={
    name:"zhangsan ",
    fa:{
        age:18
    }
}
方法一
const deepobj=JSON.parse(JSON.stringify(obj))
方法二
const _ = require('lodash');
const deepobj2=_.cloneDeep(obj)
输出结果
console.log(deepobj,deepobj2)
js 复制代码
使用了,weakmap,当函数不再使用的时候,可以垃圾回收,不会导致内存泄漏
使用闭包,实现数据的私有,避免影响全局变量
function  deepClone(target){
    const map=new WeakMap() 

    function _deepClone(target){

        if(typeof target!=='object'||target===null) { return target} // 不是引用类型的,直接返回

        if(map.has(target))
        {return map.get(target)}          //判断缓存里面是否有,有的话,直接返回就行。避免循环引用的问题

        let newTarget=Array.isArray(target)?[]:{}  // 判断是否为数组
         
        map.set(target,newTarget)  // 缓存里面没有
      
        for(let key in target){   // 循环拷贝
            if(target.hasOwnProperty(key)){
                newTarget[key]=_deepClone(target[key])
            }
        }
        return newTarget  // 返回拷贝后的对象 
 }
 return _deepClone(target)
}

new

  • 创建一个新对象
  • 让新对象的对象原型指向构造函数的原型对象
  • 执行构造函数,并把构造函数的this指向新创建出来的对象
  • 返回创建后的结果;
js 复制代码
function myNew(constructor, ...args) {
    // 创建一个新对象
    const obj = {};
    // 让新对象的原型指向构造函数的原型
    obj.__proto__ = constructor.prototype;
    // 执行构造函数,并且把 this 绑定到新对象上
    const result = constructor.apply(obj, args);
    // 若构造函数返回一个对象,则返回该对象;否则,返回新创建的对象
    return typeof result === 'object' && result!== null? result : obj;
}

instanceof

判断 是不是当前原型链上的属性

js 复制代码
function ins(target,type){
target=target.__proto__
type=type.prototype
while(true){
    if(target===null){
        return false
    }
    if(target===type){
        return true
    }
    target=target.__proto__
}
}

flat

  • 将多维数组转化为一维数组
  • 创建一个结果数组
  • this指向的是调用的数组,item就是数组里面的每一项
  • 对每一项进行判断,如果还是数组,递归调用函数。将结果和之前的结果拼接起来
  • 不是数组的话,直接将元素push进
  • 返回结果数组
js 复制代码
Array.prototype.falten= function (){
    let flat=[]
    for(let item of this){
        if(Array.isArray(item)){
            flat=flat.concat(item.falten())
        }else{
            flat.push(item)
        }
    }
    return flat
}

url解析

参考:htps://juejin.cn/post/7388057629773889562

完整的 URL 信息包括以下几点:

  • 协议(protocol):采用的协议方案;
  • 登录信息(username & password):(可选项)指定用户名和密码,用来从服务器获取资源时的认证信息;
  • 服务器地址(hostname):待访问的服务器地址。可以是域名形式也可以是 IP 地址;
  • 服务器端口号(port):;(可选项)指定服务器连接网路的端口号;
  • 带层次的文件路径(pathname):指定服务器上的文件路径来定位特指的资源;
  • 查询字符串(search):(可选项)查询字符串参数;
  • 片段标识符(hash):(可选项)用来标记已获取资源中的子资源;

数组转树 哈希解法

js 复制代码
const arr = [
  { id: 1, parentId: null, name: 'Root' },
  { id: 2, parentId: 1, name: 'Child 1' },
  { id: 3, parentId: 1, name: 'Child 2' },
  { id: 4, parentId: 2, name: 'Grandchild 1' },
]

 function arraytotree(arr){
   const map=new Map()
   for(let item of arr){     //用空间换时间 id:数组的每一项
    map.set(item.id,item)
   }
   const roots=[]  //根节点数组
   for(let item of arr){
    if(item.parentId===null){  //说明是根节点
        roots.push(item)
    }else{
        const parent=map.get(item.parentId)  //找到当前节点的父节点
        if(!parent.children){        //父节点没有children 属性,给他加一个孩子属性
            parent.children=[]
        }
        parent.children.push(item)  //把子项放入父亲的子节点中
    }
   }
}
相关推荐
暖和_白开水19 分钟前
数据分析agent (七):contextvars 模块上下文request_id
java·前端·数据分析
程序员黑豆28 分钟前
鸿蒙应用开发:Flex 组件从入门到实战
前端·华为·harmonyos
大爱编程♡28 分钟前
Vue3+TypeScript+element-plus的文章管理项目(配后端接口)-退出及文章管理页面
前端·javascript·typescript
先吃饱再说29 分钟前
React 组件设计:从 Props 传递到组件封装
前端·react.js
独立开阀者_FwtCoder33 分钟前
最近做了一个健身小程序:智形健身助手,健身的佬们来提点意见
前端·javascript·github
舒灿36 分钟前
喵ing Tab 1.0.0 正式发布
前端·ai编程
葡萄城技术团队39 分钟前
当表格数据来自外部系统:SpreadJS 如何让异步公式一键刷新
前端
小徐_233344 分钟前
Open Wot 1.0.5 发布:让 AI 接入 wot-ui,只需要两条命令
前端·uni-app·ai编程
Android研究员1 小时前
Android进阶之事件分发机制深度剖析
android·前端·面试
Csvn1 小时前
🛡️ 前端水印方案全解析——从「能被 F12 删掉」到「删不掉」的反破解实战
前端