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

前端百题斩——快手撕Call、Apply、Bind

时间:2023-03-13 08:02:20 科技观察

百题斩js中的这些“this”指针,值得理解。call、apply、bind这三个方法已经简单介绍过了。这三个方法的作用是一样的,都是可以改变this的方向,让一个对象可以调用自己没有的方法。本节将深入理解这三者的实现原理。15.1call()15.1.1基础call()方法使用指定的this值和一个或多个单独给定的参数调用一个函数。它的返回值是用调用者提供的this值和参数调用函数的返回值。如果方法没有返回值,则返回undefined。基本用法:function.call(thisArg,arg1,arg2,...)smalltestfunctionmethod(val1,val2){returnthis.a+this.b+val1+val2;}constobj={a:1,b:2};console.log(method.call(obj,3,4));//1015.1.2实现一个call函数,会进行以下步骤:获取第一个参数(注意第一个参数为null或undefined时,this指向window),构建对象,将对应的函数传入对象获取参数执行对应的函数删除对象中的函数,消除副作用并返回结果Function.prototype.myCall=function(context,...args){//获取第一个参数(注意当第一个参数为null或undefined时,this指向window),构建对象context=context?Object(context):window;//pass将相应的函数放入对象中context.fn=this;//获取参数并执行相应的函数letresult=context.fn(...args);//消除副作用deletecontext.fn;//返回resultreturnresult;}//...console.log(method.myCall(obj,3,4));//1015.2apply()15.2.1基本apply()方法调用具有给定this值的函数,并提供数组(或类数组对象)形式的参数。它的返回值是指定此值和参数的函数的结果。call()和apply()的区别是call()方法接受一个参数列表,而apply()方法接受一个参数数组;基本用法func.apply(thisArg,[argsArray])是一个小测试函数method(val1,val2){returnthis.a+this.b+val1+val2;}constobj={a:1,b:2};console.log(method.apply(obj,[3,4]));//1015.2.2apply和call的区别主要是参数的不同,所以call的实现步骤大致类似,如下图:函数.prototype.myApply=function(context,arr){context=context?Object(context):window;context.fn=this;letresult=arr?context.fn(...arr):context.fun();deletecontext.fn;returnresult;}//...console.log(method.myApply(obj,[3,4]));//1015.3bind()15.3.1基本的bind()方法创建一个新函数,当bind()被调用时,这个新函数的this被指定为bind()的第一个参数,其余参数将作为新函数调用时的参数。此函数的返回值是具有指定this值和初始参数的原始函数的副本。基本用法function.bind(thisArg[,arg1[,arg2[,...]]])小测试functionmethod(val1,val2){returnthis.a+this.b+val1+val2;}constobj={a:1,b:2};constbindMethod=method.bind(obj,3,4);console.log(bindMethod());//1015.3.2实现bind函数比较复杂,需要注意以下几点:可以改变这一点;返回一个函数;可以接受多个参数;支持咖喱形式的参数传递fun(arg1)(arg2);获取到调用bind()的返回值后,如果使用newcall(作为构造函数),则bind()传入的context是无效的。Function.prototype.myBind=function(context,...args){if(typeof(this)!=='function'){thrownewTypeError('Theboundobjectneedstobeafunction');}constself=this;//定义一个内置函数constfNOP=function(){};constfBound=function(...fBoundArgs){//使用apply改变这个当前实例的点(因为这是当前实例,实例的隐士原型有一个fNOP(fnop)的实例;fnopinstanceoffNOPistrue)returnself.apply(thisinstanceoffNOP?this:context,[...args,...fBoundArgs]);}//将调用函数的原型赋值给转换函数的原型if(this.prototype){fNOP.prototype=this.prototype;}//继承调用函数的原型fBound.prototype=newfNOP();returnfBound;}本文转载自微信公众号“抱风筝”,可通过以下二维码关注。转载本文请联系风筝持有人公众号。