apply、call、bind模拟实现
2019-02-19 本文已影响0人
Luigi_Lin
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");
}