相同点:都可以改变函数的上下文this为指定的对象
不同点:
参数接收形式:
- call接收多个参数,第一参数为this指向,后面为参数列表
Func.call(context,args1,args2,args3...)
- apply接收两个参数,第一个参数为this指向,后面为一个参数组成的数组
Func.apply(context,[args1,args2,args3...])
- bind接收参数形式与call类似,接收多个参数
Func.bind(context,args1,args2,args3...)
执行
- call、apply立即执行,且只改变一次上下文
- bind不会立即执行,会返回一个永久改变上下文this的函数
传参
- call、apply一次性传入全部参数
- bind可以分多次传入参数
手写call
实现思路:在传入的上下文对象上新增方法,即可改变函数的上下文指向为传入的对象
实现步骤:
- 获取参数,并且解构为context,和参数列表。arguments->context,args1,args2..
- 在传入的context对象中新增函数Func为方法
- 执行一次当前的方法,并且传入参数列表
- 在context中删除这个方法
- 返回值为执行结果
代码实现
Function.prototype.myCall = function(){
const [context,...args] = [...arguments];
context.fn = this;
let res = context.fn(args);
delete context.fn;
return res;
}
手写apply
实现步骤
- 传入两个参数,context和args
- 同样需要在context中添加当前函数this为一个方法
- 执行一次这个方法,需要判断是否有args参数
- 删除context中的属性
- 返回结果为执行结果
代码实现
Function.prototype.myApply = function(context,args){
context.fn = this;
let res = !args?context.fn():context.fn(...args);
delete context.fn;
return res;
}
手写bind
实现步骤
- 传入的参数和call类似,因此同样需要解构出context和args
- 需要返回一个函数,并且接收返回函数传递的值,拼接到bind的传值后面,然后调用apply方法改变this
Function.prototype.myBind = function () {
const [context, ...args] = [...arguments]
return function Fn() {
const [...bindArgs] = [...arguments]
return self.apply(context, [...args, ...bindArgs])
}
}