如何使用JS简单实现apply、call和bind方法
这篇文章主要讲解了“如何使用JS简单实现apply、call和bind方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用JS简单实现apply、call和bind方法”吧!
1.方法介绍apply、call和bind都是系统提供给我们的内置方法,每个函数都可以使用这三种方法,是因为apply、call和bind都实现在了Function的原型上(Function.prototype),而他们的作用都是给我们函数调用时显式绑定上this。下面先介绍一下它们的基本用法:
apply方法:调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
使用语法:func.apply(thisArg, [argsArray])
thisArg:在func函数调用时绑定的this值;[argsArray]:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func函数;
使用效果:
functionfoo(x,y,z){console.log(this,x,y,z)}constobj={name:'curry',age:30}/***1.将obj对象绑定给foo函数的this*2.数组中的123分别传递给foo函数对应的三个参数*/foo.apply(obj,[1,2,3])
call方法:使用一个指定的 this值和单独给出的一个或多个参数来调用一个函数。
使用语法:func.call(thisArg, arg1, arg2, ...)
thisArg:在func函数调用时绑定的this值;arg1, arg2, ...:指定的参数列表,将作为参数传递给func函数;
使用效果:
functionfoo(x,y,z){console.log(this,x,y,z)}constobj={name:'curry',age:30}/***1.将obj对象绑定给foo函数的this*2.call剩余参数中的abc分别传递给foo函数对应的三个参数*/foo.call(obj,'a','b','c')
bind方法:创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
使用语法:func.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg:调用func函数时作为this参数传递给目标函数的值;arg1, arg2, ...:当目标函数被调用时,被预置入func函数的参数列表中的参数;
使用效果:
functionfoo(...args){console.log(this,...args)}constobj={name:'curry',age:30}/***1.将obj对象绑定给foo函数的this*2.bind剩余参数中的123分别传递给foo函数中参数*3.也可在newFoo调用时传入参数,这时bind传递的参数会与newFoo调用时传递的参数进行合并*/constnewFoo=foo.bind(obj,1,2,3)newFoo()newFoo('a','b','c')
总结:
apply和call主要用于在函数调用时给函数的this绑定对应的值,两者作用类似,主要区别就是除了第一个参数,apply方法接受的是一个参数数组,而call方法接受的是参数列表。
bind也是给函数指定this所绑定的值,不同于apply和call的是,它会返回一个新的函数,新函数中的this指向就是我们所指定的值,且分别传入的参数会进行合并。
2.apply、call和bind方法的实现为了所有定义的函数能够使用我们自定义的apply、call和bind方法,所以需要将自己实现的方法挂在Function的原型上,这样所有的函数就可以通过原型链找到自定义的这三个方法了。
2.1.apply的实现Function.prototype.myApply=function(thisArg,argArray){//1.获取当前需要被执行的函数//因为myApply是需要被当前函数进行调用的,根据this的隐式绑定,此处的this就是指向当前需要被执行的函数constfn=this//2.对传入的thisArg进行边界判断if(thisArg===null||thisArg===undefined){//当传入的是null或者undefined是,被执行函数的this直接指向全局windowthisArg=window}else{//将传入的thisArg对象化,方便后面在thisArg添加属性thisArg=Object(thisArg)}//也可简单写成三元运算符://thisArg=(thisArg===null||thisArg===undefined)?window:Object(thisArg)//3.将获取的fn添加到thisArg对象上//这里使用Symbol的原因是避免外部传入的thisArg中的属性与添加fn有冲突constfnSymbol=Symbol()Object.defineProperty(thisArg,fnSymbol,{enumerable:false,configurable:true,writable:false,value:fn})//也可简单写成//thisArg[fnSymbol]=fn//4.对argArray进行判断//看是否有传入值,没有值传入就默认[]argArray=argArray||[]//5.调用获取的fn函数,并将对应传入的数组展开传递过去constresult=thisArg[fnSymbol](...argArray)//调用完后删除添加的属性deletethisArg[fnSymbol]//6.将结果返回returnresult}
测试:虽然打印出来的对象中还存在Symbol属性,实际上已经通过delete删除了,这里是对象引用的问题。
functionfoo(x,y,z){console.log(this,x,y,z)}foo.myApply({name:'curry'},[1,2,3])
2.2.call的实现call方法的实现和apply方法的实现差不多,主要在于后面参数的处理。
Function.prototype.myCall=function(thisArg,...args){//1.获取当前需要被执行的函数constfn=this//2.对传入的thisArg进行边界判断thisArg=(thisArg===null||thisArg===undefined)?window:Object(thisArg)//3.将获取的fn添加到thisArg对象上constfnSymbol=Symbol()thisArg[fnSymbol]=fn//4.调用获取的fn函数,并将对应传入的args传递过去constresult=thisArg[fnSymbol](...args)//调用完后删除添加的属性deletethisArg[fnSymbol]//5.将结果返回returnresult}
测试:
functionfoo(x,y,z){console.log(this,x,y,z)}foo.myCall({name:'curry'},1,2,3)
2.3.bind的实现bind方法的实现稍微复杂一点,需要考虑到参数合并的问题。
Function.prototype.myBind=function(thisArg,...argsArray){//1.获取当前的目标函数,也就是当前使用myBind方法的函数constfn=this//2.对传入的thisArg进行边界判断thisArg=(thisArg===null||thisArg===undefined)?window:Object(thisArg)//3.将获取的fn添加到thisArg对象上constfnSymbol=Symbol()thisArg[fnSymbol]=fn//4.定义一个新的函数functionnewFn(...args){//4.1.合并myBind和newFn传入的参数constallArgs=[...argsArray,...args]//4.2.调用真正需要被调用的函数,并将合并后的参数传递过去constresult=thisArg[fnSymbol](...allArgs)//4.3.调用完后删除添加的属性deletethisArg[fnSymbol]//4.4.将结果返回returnresult}//6.将新函数返回returnnewFn}
测试:
functionfoo(x,y,z){console.log(this,x,y,z)}constnewFoo=foo.myBind({name:'curry'},1,2)newFoo(3)
感谢各位的阅读,以上就是“如何使用JS简单实现apply、call和bind方法”的内容了,经过本文的学习后,相信大家对如何使用JS简单实现apply、call和bind方法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。