前言
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;
}
}
複製程式碼