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



防抖

  • 声明定时器
  • 返回函数
  • 判断是否有定时器,如果有,销毁定时器
  • 创建定时器,执行函数
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)  //把子项放入父亲的子节点中
    }
   }
}
相关推荐
风无雨17 分钟前
GO启动一个视频下载接口 前端可以边下边放
前端·golang·音视频
aha-凯心1 小时前
前端学习 vben 之 axios interceptors
前端·学习
熊出没1 小时前
Vue前端导出页面为PDF文件
前端·vue.js·pdf
VOLUN1 小时前
Vue3项目中优雅封装API基础接口:getBaseApi设计解析
前端·vue.js·api
用户99045017780091 小时前
告别广告干扰,体验极简 JSON 格式化——这款工具让你专注代码本身
前端
前端极客探险家2 小时前
告别卡顿与慢响应!现代 Web 应用性能优化:从前端渲染到后端算法的全面提速指南
前端·算法·性能优化
袁煦丞2 小时前
【局域网秒传神器】LocalSend:cpolar内网穿透实验室第418个成功挑战
前端·程序员·远程工作
江城开朗的豌豆2 小时前
Vuex数据突然消失?六招教你轻松找回来!
前端·javascript·vue.js
好奇心笔记3 小时前
ai写代码随机拉大的,所以我准备给AI出一个设计规范
前端·javascript
江城开朗的豌豆3 小时前
Vue状态管理进阶:数据到底是怎么"跑"的?
前端·javascript·vue.js