typescript,javascript中bind函数理解和自定义实现

一直以来觉得对typescript,javascript,还算了解平时的开发中也没有遇到过什么问题,但是今天发现一些基础理解还是不到位的。在typescript,javascript中,bind函数是一个特殊的存在,在其他语言中都没有,比如:C#,go语言。本文使用typescript开发h5游戏的过程中,因为错误使用bind功函数导致的错误,并且说明一下:typescript,javascript中bind函数,apply函数,call函数的使用方法和作用。


在基于cocos creator 开发h5的中,不可避免的会用到消息的通知。自定义了一个消息系统,可以确定的是这个消息系统没有问题,简单说明一下,EventMgr系统的几个接口,便于后面说明bind函数的问题

  1. //添加消息通知的方法
  2. EventMgr.addEventListener(eventName:string,handler:any,target:any)
  3. //消息广播
  4. EventMgr.dispatcher(eventName:string);
  5. //移除消息监听
  6. EventMgr.remove(eventName:string,handler:any,target:any)

在消息系统外,注册消息的时候如下所示:

  1. //onEnter() 中操作
  2. EventMgr.addEventListener("eventName1",this.handle.bind(this),this);
  3. //onExit() 中操作
  4. EventMgr.remove("eventName1",this.handle.bind(this),this);

以上伪代码,已经能够表达出来意思了。这写代码是有bug的。
消息可以注册成功,但是不能成功移除。原因是

this.handle.bind(this) 返回的和this.handle不是同一个函数

通过this.handle.bind()返回的是一个新的函数,新函数对this.handle进行了包装,同时指定了上下文 this。

明白了这些,解决问题就容易了。去掉this.handle.bind(this)的bind(this)。

bind函数的理解

要想深入理解bind函数就需要理解typescript和javascript中,this关键字的绑定规则。

  1. 1. 当一个函数是独立的,this执行全局对象。这种被称为默认绑定
  2. 2. 当函数作为引用属性被添加到对象中,那么this就是当前对象,这种被称为隐式绑定
  3. 3. 运用apply,call函数进行强行绑定。这种被称为显示绑定
  4. 4. new绑定就是使用new操作符是this的对象绑定

以上四种绑定规则,优先级是4>3>2>1。

了解了this关键字的绑定规则,bind的功能主要就是修改this的上下文关系。bind函数有三个功能特点

  1. 改变原函数的 this 指向,即绑定上下文,返回原函数的copy
  2. 绑定函数 被调用时,bind的额外参数将置于实参之前传递给被绑定的方法。
  3. 注意,一个 绑定函数 也能使用 new 操作符创建对象,这种行为就像把原函数当成构造器,thisArg 参数无效。也就是 new 操作符修改 this 指向的优先级更高。

今天遇到的问题就是不了解第1条规则。返回原函数的copy引起的

下面是自己实现的一个bind函数叫做weijianbind

  1. //在Function的原型上定义这个方法 接受上下文对象作为第一个参数
  2. Function.prototype.weijianbind=function(context){
  3. //错误判断
  4. if(typeOf this!=='function')return false;
  5. //保存上下文环境
  6. let _self=this;
  7. //获取除第一位context的其他参数
  8. let arg=[...arguments].slice(1);
  9. //定义一个新的函数 用apply或call方法改变其this指向为context
  10. let fn=function(){
  11. //这里的arguments是bind返回函数的参数,将他和上面的参数拼接到一起才是完整的参数
  12. let arg2=arg.concat([...arguments])
  13. //当bind遇到new时,bind 时指定的 this 值会失效,但传入的参数依然生效
  14. //需要通过查阅原型链是否有fn的方法判断遇到new
  15. if(this instanceof fn){
  16. return _self.apply(_self,arg2)
  17. }else{
  18. return _self.apply(context,arg2)
  19. }
  20. }
  21. // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
  22. fn.prototype=_self.prototype
  23. return fn
  24. }
  1. //定义一个obj对象
  2. let obj={value:'objValue'}
  3. function fa1(name,age){
  4. console.log(this.value)
  5. console.log(name,age)
  6. }
  7. fa1.prototype.friend='weijian21.top'
  8. let obj1=fa1.weijianbind(foo,'weijian21.top哈哈哈哈')
  9. obj1('18')
  10. //'objValue' this指向foo
  11. //'weijian21.top哈哈哈哈'
  12. //'18'
  13. //遇到new之后
  14. let gg=new obj1('gg')
  15. console.log(gg.friend)
  16. //undefined 因为this指向gg,gg下无value
  17. //'weijian21.top哈哈哈哈'
  18. //'gg'
  19. //'weijian21.top'

以上是对 typescirpt,javascript中bind函数的理解。下篇文章将说明一下和bind相关的另外两个函数 apply,call。

2021-07-26 22:25:42  user 阅读(323) 评论(0) 标签:typescript,javascript,bind函数,apply函数,call函数 分类:typescript javascript