call
call() 方法調用一個函數, 其具有一個指定的this值和分別地提供的參數(參數的列表)。
例如:
var foo = { x: 10 };
function test(y) {
console.log(this.x,y);
}
test.call(foo,20); //10 20
- 為達到綁定this的效果,可以將函數加到傳入的對象上進行調用。
Function.prototype.call2 = function (self) {
self.fn = this;
return self.fn();
}
但這樣傳入的對象就多了一個屬性了
- 在調用后刪除掉這個屬性
Function.prototype.call2 = function (self) {
self.fn = this;
var result = self.fn();
delete self.fn();
return result;
}
- 將提供的參數傳入
Function.prototype.call2 = function (self) {
self.fn = this;
var params = [];
for (var i = 1; i < arguments.length; i++) {
params.push(`arguments[` + i + `]`);
}
var result = eval('self.fn(' + params + ')');
delete self.fn;
return result;
}
- 當傳入對象為空時,this綁定到window
Function.prototype.call2 = function (self) {
self = self || window;
self.fn = this;
var params = [];
for (var i = 1; i < arguments.length; i++) {
params.push(`arguments[` + i + `]`);
}
var result = eval('self.fn(' + params + ')');
delete self.fn;
return result;
}
apply
與call類似,區別時apply傳入的參數列表為數組
Function.prototype.apply2 = function (self, args) {
self = self || window;
self.fn = this;
var result;
if (!args || !args.length) {
result = self.fn();
} else {
var params = [];
for (var i = 0; i < args.length; i++) {
params.push(`args[` + i + `]`);
}
result = eval('self.fn(' + params + ')');
}
delete self.fn;
return result;
}
bind
- bind會返回一個函數,該函數的this綁定到第一個參數上。
Function.prototype.bind2 = function (self) {
var fn = this;
return function () {
return fn.apply(self);
}
}
- bind返回的函數可以接收參數
Function.prototype.bind2 = function (self) {
var fn = this;
return function () {
var bindArgs = Array.prototype.slice.call(arguments);
return fn.apply(self,bindArgs);
}
}
- 調用bind的時候可以先綁定一部分參數,在調用其返回的函數時傳入的參數會跟在bind綁定的那部分參數后面
Function.prototype.bind2 = function (self) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var bindArgs = Array.prototype.slice.call(arguments);
return fn.apply(self, args.concat(bindArgs));
}
}
- 對bind返回的新函數進行構造調用時,this綁定到新構造的對象上,而非bind綁定的對象。
Function.prototype.bind2 = function (self) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
//如果this是此函數的實例,證明是被構造調用了,此時綁定新構造的對象
return fn.apply( this instanceof fBound ? this : self, args.concat(bindArgs));
}
return fBound;
}
- 維護原型關系,否則會有這樣的問題
function Test(){}
var t = Test.bind({});
var o = new t();
o instanceof Test // false
Function.prototype.bind2 = function (self) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
var f = function(){};
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return fn.apply(this instanceof fBound ? this : self, args.concat(bindArgs));
}
if(this.prototype){
f.prototype = fn.prototype;
}
fBound.prototype = new f();
return fBound;
}
6.調用bind的不是函數要報錯
if (typeof this !== "function") {//加上判斷
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}