手动实现JS bind方法

今天在学习JS设计模式的过程中,学习到代理模式 其中由一个Jquery的案例引发了一些深思,做些记录,以供加深印象:
1:首先jq中有一个$.proxy 的方法 可以实现绑定代理执行函数的对象 eg:

document.querySelector('button').addEventListener('click', function () {
     setTimeout( $.proxy(function(){
         $(this).css('color','red')
     },this),3000 )
 })

这里就实现了3000秒后$.proxy第一个参数函数 函数执行上下文为 点击的button
其中这个jq代码内部JS原理实际上就是一个bind方法,现在我们手写一下myBind实现这个JQ的proxy方法,核心代码为

if(!Function.prototype.myBind){
    Function.prototype.myBind = function(){
        if(typeof this != 'function'){// 判断调用者是不是函数
            throw new TypeError('调用myBind 需要为一个函数来触发');
        }
        var self = this; //保存原函数 即调用myBind的函数 eg: fn.mybind(obj)  this 就是fn
        var context = [].shift.call(arguments) //参数中的第一个截取下来 这个为即将转变为的执行上下文对象 eg: fn.mybind(obj)  context 就是obj
        var args = [].slice.call(arguments) //剩余的参数保存为一个数组
        return function(){
          self.apply(context, [].concat.call(args,[].slice.call(arguments)))  //绑定myBind的参数和执行myBind的参数也进行合并处理  下方有演示介绍
        }
    }
}

现在我们就自己实现了原生 js bind的方法,让我们测试一下他的效果:

var a = "window"
var obj = {
	a: 'obj'
}
function fn(b,c,d){
	console.log(this.a, arguments);
}
fn.myBind(obj,'b','c','d')('e')	//输出 obj ["b", "c", "d", "e"]
fn.myBind(obj,'b','c')('d','e')	//输出 obj ["b", "c", "d", "e"]
fn.myBind(obj)('b','c','d','e')	//输出 obj ["b", "c", "d", "e"]

这里可以看出打印的this.a 已经指向obj了 而且绑定myBind的参数和执行myBind的参数也进行了合并展示

至此我们自己手动实现JS bind就已经实现了,这里衍生一个问题,上方代码中使用了大量的 [].shift.call(arguments) [].shift.slice(arguments)这种方法,为什么不直接使用 arguments.shift() arguments.slice呢? 难道代码少写一点,看着也更直观,它不香吗? 事实确实很残酷 直接使用是不被允许的 因为arguments 并不是一个真正的数组 只是一个有length的类数组 举个例子来证明:

var a = function(){
    console.log(arguments);
    console.log(arguments instanceof Array)
    console.log(arguments.slice(1));
}
a(1,2,3,4);

执行结果会打印
1:Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
2:false
3:报错:VM1767:3 Uncaught TypeError: arguments.slice is not a function
这里从第二个打印为false 可以得出原由 arguments 并不是一个真正的数组 无法使用数组的方法 但是可以使用js的借刀杀人方法 [].shift.call [].slice.call 通过call 或者 apply 拿来主义 借用一下是没有问题的 除了这种 还有第二种方法 Array.from(arguments) 把类数组转变成真正的数组 就可以直接使用 shift slice 这些数组的自带的方法了 也是可行的。快去试试你自己手写一个js原生bind的方法吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值