前言
bind函数的主要特性:
- 创建一个新的绑定函数,这个函数与被调用的函数具有相同的函数体
- 当这个新函数被调用的时候,函数中this 指向 bind 方法中第一个参数
- 可以传递参数,bind 方法中传递的参数会在绑定函数实参之前
正文
实现bind函数
1、实现绑定指定this与传递参数
'use strict'; Function.prototype.mybind = function(context) { var _this = this; var outerArgs = Array.prototype.slice.call(arguments, 1); return function() { var innerArgs = Array.prototype.slice.call(arguments); return _this.apply(context, outerArgs.concat(innerArgs)); } }复制代码
2、当把返回的函数当作构造函数的时候,bind方法中第一个参数会被忽略(即不会绑定this)。
'use strict'; Function.prototype.mybind = function(context) { var _this = this; var outerArgs = Array.prototype.slice.call(arguments, 1); var BoundFn = function() { var innerArgs = Array.prototype.slice.call(arguments); // 当此时Fn函数返回出去,被当作构造函数,用new操作符调用的时候,this指向Fn的实例 return _this.apply(this instanceof BoundFn ? this : context, outerArgs.concat(innerArgs)); } // 把当前函数的prototype赋值给返回函数的prototype BoundFn.prototype = this.prototype; return BoundFn; } 复制代码
3、上面的代码虽然bind功能实现了,但是存在一个问题,当改变BoundFn函数实例的原型的时候,会影响到原函数的原型,相反也一样,两者的原型是同一个引用,所以需要完善一下。
'use strict'; Function.prototype.mybind = function(context) { if(typeof this !== 'function') { throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); }; var _this = this; var outerArgs = Array.prototype.slice.call(arguments, 1); var BoundFn = function() { var innerArgs = Array.prototype.slice.call(arguments); // 当此时BoundFn函数返回出去,被当作构造函数,用new操作符调用的时候,this指向BoundFn的实例 return _this.apply(this instanceof BoundFn ? this : context, outerArgs.concat(innerArgs)); }; var Fn = function() {}; fn.prototype = this.prototype; BoundFn.prototype = new Fn(); return BoundFn; }复制代码
此时bind函数已经实现了,bind函数在 ECMA-262 第五版才被加入,它可能无法在所有浏览器上运行,所以需要做下兼容:
if(!Function.prototype.bind) { Function.prototype.bind = function(context) { if(typeof this !== 'function') { throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); }; var _this = this; var outerArgs = Array.prototype.slice.call(arguments, 1); var BoundFn = function() { var innerArgs = Array.prototype.slice.call(arguments); // 当此时Fn函数返回出去,被当作构造函数,用new操作符调用的时候,this指向Fn的实例 return _this.apply(this instanceof BoundFn ? this : context, outerArgs.concat(innerArgs)); }; var Fn = function() {}; fn.prototype = this.prototype; BoundFn.prototype = new Fn(); return BoundFn; } }复制代码