手动实现 call , bind , apply
这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
call
call() 方法是预定义的 JavaScript 方法。它可以用来调用所有者对象作为参数的方法。
简单地说:通过 call(),你能够使用属于另一个对象的方法。
call 的使用
const p = {
getName: function () {
return this.name
}
}
const p1 = {
name: 'i am p1',
}
const p2 = {
name: 'i am p2',
}
console.log(p.getName.call(p1)) // i am p1
console.log(p.getName.call(p2)) // i am p2
上述代码中, 对象 p1 和 p2 是没有 getName 方法的,但是通过 call函数,使得 p1 和 p2能够调用 getName方法。
重写 call
不难发现,实际上 call函数做了两件事:
-
修改了
this指向 -
调用了 "调用 call 的函数"
所以,实现 call 的底层就是完成这两件事情。
1.在 Funtion 原型链上添加 myCall 方法,这样方便我们在 function 后调用自定义的 call 方法:
Function.prototype.mycall = function (obj) {
};
2.在参数上挂载该方法
mycall 方法传入的 obj 就是我们的主体对象,即调用者,也就是上述例子的 p1 , p2。他们本身没有 getName 方法,所以我们第一步是要给对象挂载上对应方法。这个对应方法,实际上就是 Function 原型链对象,即 this
Function.prototype.mycall = function (obj) {
obj.fn = this; // 此时this就是函数fn, 挂载方法
};
3.执行挂载方法,并保存结果
Function.prototype.mycall = function (obj) {
obj.fn = this; // 此时this就是函数fn, 挂载方法
const res = obj.fn(); // 执行fn,保存结果 res
};
4.删除挂载方法,并返回结果
Function.prototype.mycall = function (obj) {
obj.fn = this; // 此时this就是函数fn, 挂载方法
const res = obj.fn(); // 执行fn
delete obj.fn; //删除fn
return res
};
5.接受入参
Function.prototype.mycall = function (obj, ...args) {
obj.fn = this; // 此时this就是函数fn, 挂载方法
const res = obj.fn(...args); // 执行fn
delete obj.fn; //删除fn
return res
};
这样一来就实现了 call函数。
测试
const p = {
getName: function () {
return this.name
}
}
const p1 = {
name: 'i am p1',
}
const p2 = {
name: 'i am p2',
}
Function.prototype.mycall = function (obj, ...args) {
obj.fn = this; // 此时this就是函数fn, 挂载方法
const res = obj.fn(...args); // 执行fn
delete obj.fn; //删除fn
return res
};
// console.log(p.getName.mycall(p1)) // i am p1
console.log(p.getName.mycall(p1))
apply
apply 和 call 函数的差别在于参数, call 用来接收多个参数, call 用来接收数组,所以我们可以在 call 的实现基础上去实现 apply
Function.prototype.myapply = function (obj, args) {
return this.call(obj, ...args)
}
bind
bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值。
总结来说就是: bind返回函数的拷贝,并指定了函数的this指向,保存了函数的参数。
首先,bind 返回的是一个 函数,其次,这个函数的参数被保存下来了,让 obj 去调用。
Function.prototype.mybind = function (obj, ...args) {
const func = this;
return function F() { // 返回一个函数
return func.apply(obj, [...args, ...arguments]);
};
}