- 详细代码如下:
if (!Function.prototype.bind) {
Function.prototype.bind = function () {
var self = this, // 保存原函数
context = [].shift.call(arguments), // 保存需要绑定的this上下文
args = [].slice.call(arguments); // 剩余的参数转为数组
return function () { // 返回一个新函数
self.apply(context,[].concat.call(args, [].slice.call(arguments)));
}
}
}
- 详解代码
2.1 bind的简单理解
bind是用来绑定上下文的,强制将函数的执行环境绑定到目标作用域中去。与call和apply类似,但不同点在于,他不会立即执行,而是返回一个函数。因此想要自己实现一个bind函数,就必须要返回一个函数,让这个函数接受绑定的参数的上下文。
2.2 arguments
(1)定义:arguments是一个对应于传递给函数的参数的类数组对象
(2)实质是对象,typeof arguments 的结果是object。arguments对象只能在函数内部使用
(3)不是数组,类似于数组,除了length属性和索引元素之外没有任何Array属性。但是可以被转换为一个真正的数组,下图是转化为数组的4种方法
(4) 实例
2.3[].shift.call(arguments)
(1)[].shift
其实Array.prototype.shift === [].shift
,两者其实是同一个函数,只是调用的方式存在差异,一个是通过原型的方式直接在类上调用;一个是通过实例化,继承过来,然后再调用。
(2) call
call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
(3)综上:[].shift.call(arguments)这条语句的含义是将arguments转化为数组,再对其运用shift方法,得到传入的参数中的第一个参数即this
2.4 返回函数
return function () { // 返回一个新函数
self.apply(context,[].concat.call(args, [].slice.call(arguments)));
}
(1)apply函数接受两个参数(第一个参数是this上下文,第二个参数是数组列表)
(2)合并参数
① 将bind 的其余参数和调用bind后返回的函数在执行的过程中接收的参数进行拼接,作为一个数组传入apply的第二个参数中去。
② args是绑定上下文的时候(也就是bind())传递的参数,而后面的arguments则是调用bind()()第二个括号传递的参数,所以这里才会需要合并
(3)如果对于合并参数还是不太明白,可以看下下面的代码
//my_bind方法不仅可以绑定对象,还可以传参
Function.prototype.my_bind = function(context){
var args = Array.prototype.slice.call(arguments, 1);
//args [7, 8]
var self = this;
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
//innerArgs [9]
var finalArgs = args.concat(innerArgs);
//finalArgs [7, 8, 9]
return self.apply(context, finalArgs);
}
}
//测试
function a(m, n, o){
return this.name + ' ' + m + ' ' + n + ' ' + o;
}
var b = {name : 'kong'};
a.my_bind(b, 7, 8)(9); //kong 7 8 9
本文参考了博文https://blog.csdn.net/lovefengruoqing/article/details/80186401,若有兴趣的小伙伴可以看看原文章。