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

【带题提分】了解JS中bind、call、apply的异同

时间:2023-03-27 18:14:22 JavaScript

?使用方法function.call(object,arg1,arg2....)function.apply(object,[arg1,arg2,...])function.bind(object,arg1,arg2,....)都是一样的你可以改变this的方向,第一个参数是this将指向的对象。不同的是call和apply在使用的时候会自动执行函数,而bind不会。你能自己手动实现这三个方法吗?bind方法的概念:返回原函数(也称为绑定函数)的副本,调用时将this关键字设置为提供的值。并且在调用新函数时,将给定的参数列表作为原函数参数序列的前几项。function.bind(thisArg[,arg1[,arg2[,...]]])thisArg:调用绑定函数时作为this参数传递给目标函数的值。如果绑定函数是使用new运算符构造的,则忽略此值。当使用bind在setTimeout(作为回调提供)中创建函数时,作为thisArg传递的任何原始值都将转换为对象。如果绑定函数的参数列表为空,则执行范围的this将被视为新函数的thisArg。arg1,arg2,...:调用目标函数时添加到绑定函数参数列表的参数。例子:window.value=3;varfoo={值:1};函数栏(){console.log(this.value);}酒吧();//3bar.call(foo);//1//指定this绑定foo的函数,生成一个新的函数,后面运行的时候,内部this就是绑定的对象varbindFoo=bar.bind(foo);setTimeout(function(){bindFoo();},2000)//2秒后打印1这个例子可以很好理解bind的使用:bar()直接调用函数,这里的value指的是所有变量value=3bar。call(foo)这里使用call来立即改变bar中的this指向foo。Bind常用于异步。在setTimeout中,在设置的时间内,bar的this一直指向foo,所以两秒后打印的是1,而不是3。前置知识:MDN:绑定函数也可以使用new操作符构造,相当于目标函数已经构建。Aprovidedthis值被忽略,但前置参数仍然提供给模拟函数。特别说明:绑定函数new实例化后,需要继承原函数的原型链方法,绑定过程中提供的this被忽略(继承原函数的this对象),但参数会还是用代码实现constwang={age:18,love:'coding',hello:function(age,love){if(age)this.age=age;如果(爱)this.love=love;console.log("helloworld,我是ghostwang,"+this.age+","+this.love);}};constye={age:19,love:'sleeping'};//wang.hello.myCall(ye,0);函数。prototype.myBind=function(){if(typeofthis!=='function'){thrownewTypeError(this+'必须是一个函数');}consttarget=Array.from(arguments)[0];//第一个参数是thisconstargs=Array.from(arguments).slice(1);常量自我=这个;letfBound=function(){const_this=thisinstanceofself?这:目标;//检测是否使用new创建returnself.apply(_this,args);}/**假设我们调用调用bindC的函数,将fBound的prototype原型对象指向C的prototype原型对象(上例中为self),那么如果将fBound作为构造函数(使用newoperator)来实例化一个对象,那么这个对象也是C的一个实例,这个instanceofself是它会返回真值。此时将self指向新建对象的this,达到nativebind的效果(指定的this不再固定)。否则,使用oThis,即绑定指定的this。**/if(this.prototype){fBound.prototype=this.prototype}returnfBound;}constfoo=wang.hello.myBind(ye);constfoo2=wang.hello.myBind(ye,10,'妈妈爱u');constnFoo=newfoo2();//你好世界,我是ghostwang,10,妈妈喜欢ufoo();//你好世界,我是ghostwang,19,sleepingcall方法概念:function.call(thisArg,arg1,arg2,...);thisArg:fun函数运行时指定的this值。需要注意的是,指定的this值不一定是函数执行时真正的this值。如果函数处于非严格模式,指定为null和undefined的this值将自动指向全局对象(在浏览器中为window对象),而原始值(number、string、boolean)的this值)将指向原始值的自动包装对象。arg1,arg2,...:指定的参数列表。varobj={name:'segmentfault'};functionfn(){//console.log(this);console.log(this.name);}fn();//undefinedfn.call(obj);//Segmentfault理解:先找call方法,通过原型链的查找找到Function.prototype上的call方法;然后,改变fn函数中的this点,执行fn。varobj={name:'wc'};functionfn(age,country){console.log(this.name+'-'+age+'-'+country);}fn.call(obj,18,'中国');//wc-19-China理解:传入参数,需要对参数进行扩展,这是与apply方法唯一的区别。代码实现Function.prototype.myCall=function(){constargumentsArr=Array.from(arguments);consttarget=argumentsArr[0];if(!target){//判断是节点还是浏览器环境target=typeofwindow===undefined?全局:窗口;}target.fn=这个;//这里的this指向之前的对象,是被调用函数的原型对象//现在taget的fn属性是缓存的一个函数,需要改变这个函数内部的this。谁在前面,this指向谁,所以现在这是tagetconstres=target.fn(argumentsArr.slice(1));删除target.fn;returnres;}constwang={age:18,love:'coding',hello:function(){console.log("helloworld,我是zhou,"+this.age+","+this.love);}};constye={age:19,love:'sleeping'};wang.hello.myCall(ye);//helloworld,我是ghostwang,19,sleeping总结:call方法的第一个参数用于改变调用方法在函数中,指向this,但是如果传入一个null/undefined值,thisthis会指向windowcall方法,需要根据形参的个数把实参传入call方法,最后在call函数体中用参数执行this指向的Function,一般指的是函数callscallapply方法概念:使用给定的this值调用函数,并将参数作为数组(或类数组对象)提供。func.apply(thisArg,[argsArray])thisArg:可选。func函数运行时使用的this值。请注意,这可能不是方法看到的实际值:如果函数处于非严格模式,指定null或undefined将自动替换为对全局对象的引用,并且原始值将被包装。argsArray:可选。一个数组或类数组对象,其元素将作为单独的参数传递给func函数。如果这个参数的值为null或者undefined,表示不需要传入任何参数。代码实现constwang={age:18,love:'coding',hello:function(){console.log("hello世界,我是zhou,"+this.age+","+this.love);}};constye={age:19,love:'sleeping'};Function.prototype.myApply=function(){constargumentsArr=Array.from(arguments);consttarget=argumentsArr[0];if(!target){//判断是节点还是浏览器环境target=typeofwindow===undefined?全局:窗口;}target.fn=这个;//这里this指向之前的对象,也就是被调用的函数Prototype对象//现在taget的fn属性是缓存被调用的函数,需要改变这个函数内部的this,谁在前面,this指向谁,所以现在这是tagetconstres=target.fn(...argumentsArr.slice(1));删除target.fn;returnres;}wang.hello.myApply(ye);//你好世界,我是zhou,19岁,正在睡觉