You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Function.prototype.defineBind=function(obj){letargs=Array.prototype.slice.call(arguments,1);letfn=this;//创建中介函数letfn_=function(){};// 上面说的Fn2就是这里的boundletbound=function(){letparams=Array.prototype.slice.call(arguments);//通过constructor判断调用方式,为true this指向实例,否则为objfn.apply(this.constructor===fn ? this : obj,args.concat(params));};fn_.prototype=fn.prototype;bound.prototype=newfn_();returnbound;};
最后再用一个报错润色一下:
Function.prototype.defineBind=function(obj){if(typeofthis!=="function"){thrownewError("Function.prototype.bind - what is trying to be bound is not callable");};letargs=Array.prototype.slice.call(arguments,1);letfn=this;//创建中介函数letfn_=function(){};// 上面说的Fn2就是这里的boundletbound=function(){letparams=Array.prototype.slice.call(arguments);//通过constructor判断调用方式,为true this指向实例,否则为objfn.apply(this.constructor===fn ? this : obj,args.concat(params));};fn_.prototype=fn.prototype;bound.prototype=newfn_();returnbound;};
Function.prototype.defineBind=function(context, ...rest){if(typeofthis!=="function"){thrownewError("Function.prototype.bind - what is trying to be bound is not callable");}varself=this;returnfunctionF(...args){if(thisinstanceofF){returnnewself(...rest, ...args);}returnself.apply(context,rest.concat(args));};};
The text was updated successfully, but these errors were encountered:
今天刷题的时候看到一个有关
call
和apply
的奇葩描述,觉得挺有意思的,于是重新把call
和apply
的逻辑手写了一遍,温故而知新~这么说还确实有几分道理,下面就通过这个描述重新手写一下
apply
和bind
!前提
首先准备三个对象:
猫
,狗
,奥特曼
:准备好之后,我们先来实现一下
call
。call
狗吃鱼
的话需要这样使用:猫.吃鱼.call(狗, 鱼)
,可以看出来调用call
的是猫
上面的吃鱼
方法,而参数是狗
和鱼
,所以应该是这样使用:对于
call
方法,大概的逻辑是这样的:按照上面的逻辑,我们可以这样写:
这样,一个自定义的
call
基本上就完成啦!现在来测试一下:现在
狗
可以吃鱼
了,猫
可以打小怪兽
了!现在我们让狗多吃几种鱼,我们先来简单改一下猫的吃鱼:
然后我们再这样调用:
这样就可以吃各种鱼了,当然是用
arguments
来操作参数也是可以的。apply
apply
和call
用法基本类似,区别就在于,第二个参数是数组,我们可以这样写:现在再来调用一下,看看写的对不对:
成功!🎉
bind
既然
call
和apply
都实现了,那稍微有点难度的bind
也来实现一下好了,毕竟它们是铁三角
嘛。我们先来捋一下
bind
都有哪些东西:bind
也是用来转换this
的指向的。bind
不会像它们两个一样立即执行,而是返回了一个绑定this
的新函数,需要再次调用才可以执行。bind
支持函数柯里化。bind
返回的新函数的this
是无法更改的,call
和apply
也不可以。我们一步一步来写,首先写一个最简单的:
然后给它加上传参的功能,变成这样:
接着给它加上柯里化:
现在的
defineBind
差不多已经初具bind形
了,让它升级成真正的bind
,还有一个细节:这个意思其实就是让我们自定义
this
的判断和原型继承,所以比较难的来了,先了解一点:构造函数的实例的构造器指向构造函数本身:并且在构造函数运行时,内部的
this
是指向实例的(谁调用,this
就指向谁),所以this.constructor
是指向构造函数的:那是不是就可以通过改变
this.contructor
的指向来改变原型继承呢?答案当然是对的!当返回函数作为构造函数的时候,
this
指向的应该是实例,当返回函数作为普通函数的时候,this
指向的有应该是当前上下文:这样,一个
bind
基本上就结束了,而且返回的构造函数所产生的实例也不会影响到构造函数。但是!直接修改实例原型会影响构造函数!
那这个怎么办呢?要是构造函数的原型里啥都没有就好了,这样就不会相互影响了……blablabla……
写一个小例子,用一个中介,让构造函数的原型只能影响到实例,影响不到其他东西:
给Fn2加了一层
__proto__
的方式,让Fn2的原型指向了一个实例,而实例的原型是Fn,这样Fn2的改变就不会影响到Fn了(当然通过__proto__.__proto__
还是一样能修改)!最后再用一个报错润色一下:
手写
bind
完毕!最后用狗吃鱼来验证一下:
最后再附上一个es6版本的手写bind,大家可以过一下,还是比较清晰的:
The text was updated successfully, but these errors were encountered: