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

50行javaScript代码实现简单版的call,apply,bind【中级前端面试基础】

时间:2023-03-30 17:30:12 CSS

在实现自己的call,apply,bind之前,需要复习一下这个。所谓this其实可以理解为一个指针:其实this的指向始终坚持一个原则:this始终指向最后调用它的对象,this才是本质。最重要的一点就是this的四点:当正常调用this的函数时,指向window,如果当前处于严格模式,则指向undefinedfunctiontest(){console.log(this);};测试();指向window输出如下代码://Window{speechSynthesis:SpeechSynthesis,caches:CacheStorage,localStorage:Storage,sessionStorage:Storage,webkitStorageInfo:DeprecatedStorageInfo...}strictmode'usestrict';functiontest(){console.log(this);};test();//当this定位到undefined时,调用obj.fn()形式的函数时,指向objvarobj={name:'segmentFault',foo:function(){console.log(this.name);}}obj.foo();//'segmentFault'也可以做这个功能test(){console.log(this.name);}varobj={name:'qiutc',foo:test}obj.foo();//'qiutc'call时,apply被添加,this点改变functiona(a,b,c){console.log(this.name);console.log(a,b,c)}constb={name:"segmentFault"}a.call(b,1,2,3)//输出segmentFault和1,2,3functiona(a,b,c){console.log(this.name);console.log(a,b,c)}a.apply(b,[1,2,3])//遇到bind后输出segmentFault和1,2,3:functiona(){console.log(this.name);}constb={name:"segmentFault"}a.bind(b,1,2,3)此时控制台没有代码输出,因为bind会重新生成并返回一个this指向第一个参数函数的函数a(){console.log(this.name);}constb={name:"segmentFault"}constc=a.bind(b,1,2,3)c()//此时输出segmentFault,正式开始自己实现call:定义自己的myCall函数原型上的方法:Function.prototype.myCall=function(context,...arg){constfn=Symbol('temporaryattribute')context[fn]=thiscontext[fn](...arg)deletecontext[fn]}四行代码实现了一个简单的调用,思路如下:通过object属性调用函数,this函数中的this指向这个对象。每次调用一个新的symbol属性,调用完成后删除symbol属性,用在调用mycall方法的函数的函数参数中...arg是将多个参数塞入一个数组。当函数内部使用变量arg时,它是一个包含所有形参的数组。调用context[fn](...arg)时,...arg是展开数组,传递参数是为了调用函数。为了简化,今天不做类型判断和errormargin处理,只是把原理说清楚自己实现apply并在函数原型上定义自己的myApply方法://ImplementyourownmyApplyFunction.prototype.myApply=function(context,arg){constfn=Symbol('temporaryattribute')context[fn]=thiscontext[fn](...arg)deletecontext[fn]}constobj2={a:1}test.myApply(obj2,[2,3,4])一样,只是apply传递的第二个参数是一个数组,这里我们只需要在调用时用参数扩充数组即可自己实现bind:bind与apply和call的本质区别是bind不会改变原函数的this点,只会返回一个新功能(我们想要这个指向的那个),并且不会被调用。但是apply和call会改变原来函数的this点,直接调用bind。专门用于写框架源码,比如koa://实现自己的myBindFunction.prototype.myBind=function(context,...firstarg){constthat=thisconstbindFn=function(...secoundarg){returnthat.myCall(context,...firstarg,...secoundarg)}bindFn.prototype=Object.create(that.prototype)returnbindFn}varfnbind=test.myBind(obj,2)fnbind(3)在同理,自己在原型上定义myBind方法。劫持并保留原来调用mybind方法的对象返回一个新的函数。新函数的内部this点已经确定。我们使用我们的mycall方法一步步学习。建议按照本文顺序进行封装。这相对容易。当然bind需要判断是否是新的调用。完整版bindFunction.prototype.myBind=function(objThis,...params){constthisFn=this;//存储源函数和上面的params(函数参数)//SecondParams到返回函数secondParamsletfToBind=function(...secondParams){console.log('secondParams',secondParams,...secondParams)constisNew=thisinstanceoffToBind//this是否是fToBind的实例,即返回的fToBind是否被newconstcontext=isNew调用?这:对象(objThis)//新调用绑定this,否则绑定传入的objThisreturnthisFn.call(context,...params,...secondParams);//使用call调用source函数绑定指向this和Pass参数,返回执行结果};fToBind.prototype=Object.create(thisFn.prototype);//将源函数的原型复制到fToBindreturnfToBind;//返回复制的函数};觉得写的好可以给个star,欢迎加入我们的前端交流群~:现在人数超过100人,只能加我,然后拉你进群!!..]

猜你喜欢