bind函数介绍
bind
函数实际上是柯理化思想。大函数执行返回一个小函数,执行大函数,把需要准备的内容准备好、当前大函数的执行上下文因为小函数的引用关系就不能销毁了,形成了闭包。这样事先准备好的内容就能保存下来,当执行小函数时就会用到大函数里保存的信息。
这相当于大函数预先把信息存储起来,以后用的时候直接在小函数中调用即可。
实现bind函数
- 最外围是一个立即执行函数,在立即执行函数中完成使用自定义
bind
替换Function.prototype.bind
。直接上代码喽,讲解写在注释中。
// 如果让我们自己实现一个bind,该怎么写呢
~function anonymous(proto){
/**
** context
*/
function bind(context) {
// bind 中的 this =>(指向)需要最终执行的函数
//js中 null == undefined, 不传参也是undefined。所以null、undefined、null都可以用是否==undefined 判断
if (context == undefined) { // 给context一个默认值
context = window;
}
// 拿其余的参数: arguments 是类数组,我们借用数组的方法来处理
var args = [].slice.call(arguments, 1); // 第一个参数是context.相当于 Array.prototype.slice.call(arguments, 1);
var _this = this; // 需要执行的函数
// bind需要返回一个新的函数,这个新的函数中需要执行 _this 函数
// 牵涉到事件处理时,这个匿名函数中还需要传参数,比如时间对象ev
return () => {
var innerArgs = [].slice.call(arguments, 0);
_this.apply(context, args.concat(innerArgs));
}
}
proto.bind = bind; // Function原型中的bind替换为我们自己的
}(Function.prototype);
- 上面是老语法啦,怎么利用
es6
的语法来实现呢?顺便给出call
函数的实现思路。
// es6语法重写自定义bind
~function(proto) {
function bind(context = window, ...outerArgs) {
// 经过测试,apply 传递多个参数时,性能不如call
return (...innerArgs) => {
this.call(context, ...outerArgs.concat(innerArgs)); // 箭头函数中的this是外围执行上下文中的this
};
}
function call(context = window, ...args) {
// 必须保证context 是引用类型,不能是基本类型
context === null ? context = window:null;
let type = typeof context;
if (type !== 'object' && type !== 'function' && type != 'symbol') { // 基本类型
switch(type) {
case 'number':
context = new Number(context);
break;
case 'boolean':
context = new Boolean(context);
break;
case 'string':
context = new String(context);
break;
}
}
context.$fn = this;
let result = context.$fn(...args);
delete context.$fn;
return result;
}
proto.bind = bind;
proto.call = call;
}(Function.prototype);
至此,全文结束。欢迎大家给出更合理的实现思路。