当前位置: 首页 > Web前端 > HTML

前端开发进阶核心知识1.3我们不背API,只实现API

时间:2023-03-28 19:39:22 HTML

有时候面试官并不强制开发者准确背API,相反,面试官喜欢告诉面试官如何使用API并让面试官实现API。实现一个API可以检验面试官对API的理解程度,更能体现开发者的编程思维和能力。对于有上进心的前端工程师来说,模仿和实现一些经典的方法应该是“家常便饭”,这是一个比较基本的要求实现方法1.JQuery的offset()首先要了解JQuery的offset().top,dom元素的offsetTop,scrollTopoffset().top返回元素与文档之间的垂直距离,即相对于文档的垂直偏移量定位固定。没有定位的祖先元素,它们也是相对于文档的。当元素的父元素可滚动时,无论滚动到哪里,这个值都不会改变。scrollTop返回元素滚动条的滚动距离。理解后,可以尝试使用offsetTop和scrollTop实现offset().top,遍历元素的祖先元素,找到第一个具有定位功能的祖先元素offset(node){varresult={top:0,left:0}vargetOffset=function(node,init){if(node.nodeType!=1){返回}position=window.getComputedStyle(node).positionif(position==='static'&&typeofinit==='undefined'){getOffset(node.parentNode)return}result.top=result.top+node.offsetTop-node.scrollTopresult.left=result.left+node.offsetLeft-node.scrollLeftif(position==='fixed'){return}getOffset(node.parentNode)}if(window.getComputedStyle(node).display==='none'){returnresult}letpositiongetOffset(node)returnresult}if元素的显示为none,返回空值,如果不开始遍历。初始计算元素,得到元素的offsetTop,即到最近定位的祖先元素的垂直距离。如果元素是固定的,那么它的offsetTop的对象就是document,不遍历直接返回值。直接遍历找到最近定位的祖先元素,找到时计算值,得到祖先元素的offsetTop,因为越向下滚动,元素越靠近文档顶部,所以滚动高度scrollTop应减去。如果祖先固定,其offsetTop的对象为文档,则不遍历直接返回值,否则继续上述过程,直到遍历完祖先节点。2.Arrayreduce1.reduce1.1的经典应用顺序运行Promiseconstfan=(r)=>newPromise((res,rej)=>{setTimeout(()=>{console.log('p1run');res(r+1)})})constfbn=(r)=>newPromise((res,rej)=>{setTimeout(()=>{console.log('p2run');res(r+2)})})varfnArr=[fan,fbn]construnPromise=(arr,val)=>arr.reduce((pre,cur)=>pre.then(cur),Promise.resolve(val))runPromise(fnArr,3).then(res=>{console.log(res);//p1runp2run6})1.2函数方法pipe,pipe(a,b,c)是柯里化函数,返回A函数,函数将完成调用(...args)=>c(b(a(...args)))functionf1(a){a+='f1'returna}functionf2(a){a+='f2'returna}functionf3(a){a+='f3'returna}functionf4(a){a+='f4'returna}constpipe=(...funs)=>(args)=>funs.reduce((pre,cur)=>cur(pre),args)fn=pipe(f1,f2,f3,f4)console.log(fn('f'));//ff1f2f3f42.reduce的实现reduces,如果不传入第二个参数,会把数组的第一项作为回调函数的第一个参数,所以需要判断是否是第二个参数传入,并执行相应的操作Array.prototype.newReduce=function(fn,pre){vararr=thisvarresult=typeofpre==='undefined'?arr.shift():prevarstartPoint=pre?0:1for(vari=0;ia(b(c(args)))调用1.使用reduce和PromiseCompose=(...args)=>{实现constpromiseinit=args.pop()return(...arg)=>{returnargs.reverse().reduce((pre,cur)=>pre.then(res=>cur(res)),Promise.resolve(初始化(...arg)))}}2。只需使用reducefunctioncompose(...funcs){if(funcs.length===0){returnarg=>arg}if(funcs.length===1){returnfuncs[0]}returnfuncs.reduce((a,b)=>(...args)=>a(b(...args)))}四、bind的高级实现第一节指出bin返回的函数为as构造a时function,new对this的绑定优先级比较高,所以在实现bind的时候一定要考虑到这个因素。为了接收bind返回的函数传入的参数,还需要传参Function.prototype.newBind=function(context){vara=thisvarargsArr=Array.from(arguments)varF=function(){}F.prototype=this.prototypevarfn=function(){finalArgs=argsArr.concat(Array.from(arguments))返回a.apply(thisinstanceofF?this:context||this,finalArgs.slice(1))}fn.prototype=newF()returnfn}varaaa=1varobj={aaa:2}functionbindFn(...arg){控制台.log(this.aaa);console.log(arg);}varffn=bindFn.newBind(obj,'a')ffn('b')//2['a','b']varfhn=newffn('c')//undefined['a','c']在返回函数的函数体中,使用concat将传入的参数存储在参数数组中并传递下去,所以bindFn函数可以将新函数传入的参数分别为这里接收到,声明了F函数,它的原型对象指向newBind函数的原型对象,返回的fn函数的原型对象指向F原型对象。如果fn作为构造函数,按照new的流程,声明一个空对象,对象的原型指针指向构造函数fn的原型对象,即函数F的原型对象,然后指向this到对象。所以执行这个instanceofF判断this是否在F函数的原型链上。如果是,则表示调用了new,可以传入this。如果不是,则传入newBind的第一个参数,如果参数不存在,则返回当前的this。5.apply的实现既然bind的实现使用了apply,那么我们看看apply是如何实现的c=3functionfun(a,b){returnthis.c+a+b}letsym=Symbol('a')varobj={c:4}Function.prototype.applyFn=function(obj,arr){if(arr===null&&typeofarr==='undefined'){arr=[]}if(obj===null&&typeofobj==='undefined'){obj=window}obj=newObject(obj)varsym=Symbol('key')obj[sym]=thisvarres=obj[sym](...arr)deleteobj[sym]返回res}console.log(fun(1,2));console.log(fun.applyFn(obj,[1,2]));这里,this的隐式绑定用于创建一个唯一的Symbol作为对象的键,它的值为目标函数。调用后删除该属性并返回结果。