当前位置: 首页 > 科技观察

十种常见的前端手写功能你都知道吗?

时间:2023-03-14 21:54:09 科技观察

高楼拔地而起,地基牢固,方能立于不败之地。今天给大家带来的是10个常用的JavaScript手写函数,重要的地方都加了注释。有些是从别人那里借来的,有些是自己写的。如果有不准确的地方,请指正。1.防抖功能debounce(fn,delay){lettimerreturnfunction(...args){if(timer){clearTimeout(timer)}timer=setTimeout(()=>{fn.apply(this,args)},delay)}}//测试函数task(){console.log('runtask')}constdebounceTask=debounce(task,1000)window.addEventListener('scroll',debounceTask)2.节流函数throttle(fn,delay){letlast=0//最后一次触发时间return(...args)=>{constnow=Date.now()if(now-last>delay){last=nowfn.apply(this,args)}}}//测试functiontask(){console.log('runtask')}constthrottleTask=throttle(task,1000)window.addEventListener('scroll',throttleTask)3,深拷贝函数deepClone(obj,cache=newWeakMap()){if(typeofobj!=='object')returnobj//普通类型,直接返回if(obj===null)returnobjif(cache.get(obj))returncache.get(obj)//防止循环引用,程序进入死循环if(objinstanceofDate)returnnewDate(obj)if(objinstanceofRegExp)returnnewRegExp(obj)//找到原型上的构造函数,原型上的构造函数指向constructorofthecurrentobjectletcloneObj=newobj.constructor()cache.set(obj,cloneObj)//缓存复制对象,用于处理循环引用for(letkeyinobj){if(obj.hasOwnProperty(key)){cloneObj[key]=deepClone(obj[key],cache)//递归复制}}returncloneObj}//测试constobj={name:'Jack',address:{x:100,y:200}}obj.a=obj//循环引用constnewObj=deepClone(obj)console.log(newObj.address===obj.address)//false4,实现PromiseclassMyPromise{constructor(executor){//executor执行器this.status='pending'//等待状态this.value=null//成功或失败参数this.fulfilledCallbacks=[]//成功函数队列this.rejectedCallbacks=[]//失败函数队列constthat=thisfunctionresolve(value){//成功方法if(that.status==='pending'){that.status='resolved'that.value=valuethat.fulfilledCallbacks.forEach(myFn=>myFn(that.value))//执行回调方法}}functionreject(value){//failedmethodif(that.status==='pending'){that.status='rejected'that.value=valuethat.rejectedCallbacks.forEach(myFn=>myFn(that.value))//执行回调方法}}try{executor(resolve,reject)}catch(err){reject(err)}}then(onFulfilled,onRejected){if(this.status==='pending'){//waitingstatus,Addacallbackfunctiontothesuccessfulfunctionqueuethis.fulfilledCallbacks.push(()=>{onFulfilled(this.value)})//等待状态,添加回调函数到失败函数队列this.rejectedCallbacks。脓h(()=>{onRejected(this.value)})}if(this.status==='resolved'){//支持同步调用console.log('this',this)onFulfilled(this.value)}if(this.status==='rejected'){//支持同步调用onRejected(this.value)}}}//测试函数fn(){returnnewMyPromise((resolve,reject)=>{setTimeout(()=>{if(Math.random()>0.6){resolve(1)}else{reject(2)}},1000)})}fn().then(res=>{console.log('res',res)//res1},err=>{console.log('err',err)//err2})5.异步控制并发函数limitRequest(urls=[],limit=3){returnnewPromise((resolve,reject)=>{constlen=urls.lengthletcount=0//当前任务数conststart=async()=>{consturl=urls.shift()//从数组中获取第一个任务if(url){try{awaitaxios.post(url)if(count==len-1){//上一个任务成功resolve()}else{count++//成功,开始下一个任务start()}}catch(e){if(count==len-1){//上一个任务失败resolve()}else{count++//失败,开始下一个任务start()}}}}//开始限制任务while(limit>0){start()限制-=1}})}//测试limitRequest(['http://xxa','http://xxb','http://xxc','http://xxd','http://xxe'])6、ES5继承(寄生组合继承)functionParent(name){this.name=name}Parent.prototype.eat=function(){console.log(this.name+'iseating')}functionChild(name,age){Parent.call(this,name)this.age=age}Child.prototype=Object.create(Parent.prototype)Child.prototype.contructor=ChildChild.prototype.study=function(){console.log(this.name+'isstudying')}//测试letchild=newChild('xiaoming',16)console.log(child.name)//xiaomingchild.eat()//xiaomingisingchild.study()//xiaomingistudying7、数组排序sortsorting//对数字进行排序,简写为constarr=[3,2,4,1,5]arr。sort((a,b)=>a-b)console.log(arr)//[1,2,3,4,5]//对字母进行排序,简写constarr=['b','c','a','e','d']arr.sort()console.log(arr)//['a','b','c','d','e']冒泡排序函数bubbleSort(arr){letlen=arr.lengthfor(leti=0;iarr[j+1]){letnum=arr[j]arr[j]=arr[j+1]arr[j+1]=num}}//每次遍历结束,可以找到一个最大值放在数组的末尾}returnarr}//测试console.log(bubbleSort([2,3,1,5,4]))//[1,2,3,4,5]8.数组去重Set去重cosntnewArr=[...newSet(arr)]Array.from去重constnewArr=Array.from(newSet(arr))indexOf去重函数resetArr(arr){letres=[]arr.forEach(item=>{if(res.indexOf(item)===-1){res.push(item)}})returnres}//测试constarr=[1,1,2,3,3]console.log(resetArr(arr))//[1,2,3]9.获取url参数URLSearchParams方法//创建一个URLSearchParams实例consturlSearchParams=newURLSearchParams(window.location.search);//将键值对列表转换为一个对象constparams=Object.fromEntries(urlSearchParams.entries());拆分方法函数getParams(url){constres={}if(url.includes('?')){conststr=url.split('?')[1]constarr=str.split('&')arr.forEach(item=>{constkey=item.split('=')[0]constval=item.split('=')[1]res[key]=decodeURIComponent(val)//解码})}returnres}//testconstuser=getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16')console.log(user)//{user:'阿飞',age:'16'}10.事件总线|发布订阅模式cache[name]=[fn]}}off(name,fn){consttasks=this.cache[name]if(tasks){constindex=tasks.findIndex((f)=>f===fn||f.callback===fn)if(index>=0){tasks.splice(index,1)}}}emit(name,once=false){if(this.cache[name]){//创建一个副本,如果回调函数继续注册同一个事件,会造成死循环consttasks=this.cache[name].slice()for(letfnoftasks){fn();}if(once){deletethis.cache[name]}}}}//测试consteventBus=newEventEmitter()consttask1=()=>{console.log('task1');}consttask2=()=>{console.log('task2');}eventBus.on('task',task1)eventBus.on('task',task2)eventBus.off('task',task1)setTimeout(()=>{eventBus.emit('task')//task2},1000)以上是工作或求职中最常用的手写功能,你都掌握了吗?