typescript,javascript中bind函数理解和自定义实现
一直以来觉得对typescript,javascript,还算了解平时的开发中也没有遇到过什么问题,但是今天发现一些基础理解还是不到位的。在typescript,javascript中,bind函数是一个特殊的存在,在其他语言中都没有,比如:C#,go语言。本文使用typescript开发h5游戏的过程中,因为错误使用bind功函数导致的错误,并且说明一下:typescript,javascript中bind函数,apply函数,call函数的使用方法和作用。
在基于cocos creator 开发h5的中,不可避免的会用到消息的通知。自定义了一个消息系统,可以确定的是这个消息系统没有问题,简单说明一下,EventMgr系统的几个接口,便于后面说明bind函数的问题
//添加消息通知的方法
EventMgr.addEventListener(eventName:string,handler:any,target:any)
//消息广播
EventMgr.dispatcher(eventName:string);
//移除消息监听
EventMgr.remove(eventName:string,handler:any,target:any)
在消息系统外,注册消息的时候如下所示:
//onEnter() 中操作
EventMgr.addEventListener("eventName1",this.handle.bind(this),this);
//onExit() 中操作
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. 当一个函数是独立的,this执行全局对象。这种被称为默认绑定
2. 当函数作为引用属性被添加到对象中,那么this就是当前对象,这种被称为隐式绑定
3. 运用apply,call函数进行强行绑定。这种被称为显示绑定
4. new绑定就是使用new操作符是this的对象绑定
以上四种绑定规则,优先级是4>3>2>1。
了解了this关键字的绑定规则,bind的功能主要就是修改this的上下文关系。bind函数有三个功能特点
改变原函数的 this 指向,即绑定上下文,返回原函数的copy
当 绑定函数 被调用时,bind的额外参数将置于实参之前传递给被绑定的方法。
注意,一个 绑定函数 也能使用 new 操作符创建对象,这种行为就像把原函数当成构造器,thisArg 参数无效。也就是 new 操作符修改 this 指向的优先级更高。
今天遇到的问题就是不了解第1条规则。返回原函数的copy引起的
下面是自己实现的一个bind函数叫做weijianbind
//在Function的原型上定义这个方法 接受上下文对象作为第一个参数
Function.prototype.weijianbind=function(context){
//错误判断
if(typeOf this!=='function')return false;
//保存上下文环境
let _self=this;
//获取除第一位context的其他参数
let arg=[...arguments].slice(1);
//定义一个新的函数 用apply或call方法改变其this指向为context
let fn=function(){
//这里的arguments是bind返回函数的参数,将他和上面的参数拼接到一起才是完整的参数
let arg2=arg.concat([...arguments])
//当bind遇到new时,bind 时指定的 this 值会失效,但传入的参数依然生效
//需要通过查阅原型链是否有fn的方法判断遇到new
if(this instanceof fn){
return _self.apply(_self,arg2)
}else{
return _self.apply(context,arg2)
}
}
// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
fn.prototype=_self.prototype
return fn
}
//定义一个obj对象
let obj={value:'objValue'}
function fa1(name,age){
console.log(this.value)
console.log(name,age)
}
fa1.prototype.friend='weijian21.top'
let obj1=fa1.weijianbind(foo,'weijian21.top哈哈哈哈')
obj1('18')
//'objValue' this指向foo
//'weijian21.top哈哈哈哈'
//'18'
//遇到new之后
let gg=new obj1('gg')
console.log(gg.friend)
//undefined 因为this指向gg,gg下无value
//'weijian21.top哈哈哈哈'
//'gg'
//'weijian21.top'
以上是对 typescirpt,javascript中bind函数的理解。下篇文章将说明一下和bind相关的另外两个函数 apply,call。