原理
三个方法都是为了改变
this指向。主要区别:call和apply都是立即执行,call的传参是一个一个传,apply是直接传的数组;bind不会立即执行,而是返回一个新函数,传参也是一个一个,另外它可以在调用bind时和调用返回的新函数时都传入参数。
- 先找到调用这三个方法的对象:我们知道一个方法的调用对象其实就是该方法里面的
this,我们把它命名为fn; - 要改变
this指向其实跟上面的原理一样,用需要改变this指向的目的对象(thisArg)调用fn就可以了;但是thisArg里面没有fn方法,可以给thisArg里面加个属性,并把fn赋值给他,调用完之后删除即可。 - 这里定义的
fn属性会存在传入的thisArg本身可能就有这个属性,这就会导致原属性值被覆盖。解决方案可以使用Symbol来做属性名,这样就不会存在同名了。
源码
Function.prototype.myCall = function(thisArg, ...params){
// 当前的this就是调用这个方法的对象
var fn = this;
// this指向目标为null或undefined 直接返回window,否则返回Object包装后的对象(主要为了把简单类型的值转换成包装对象)
thisArg = thisArg == null ? window : Object(thisArg)
// 在thisArg中加个属性为fn,且值为fn,并调用就相当于隐式绑定this指向为thisArg了
thisArg.fn = fn
var result = thisArg.fn(...params)
// 删除添加的fn属性
delete thisArg.fn
return result
}
// 手写apply
Function.prototype.myApply = function(thisArg, params){
var fn = this
thisArg = thisArg == null ? window : Object(thisArg)
thisArg.fn = fn
var reslut = thisArg.fn(...params)
delete thisArg.fn
return result
}
// 手写bind
Function.prototype.myBind = function(thisArg, ...params1){ // 接收调用bind时传入的参数
var fn = this
thisArg = thisArg == null ? window : Object(thisArg)
return function(...params2){ // 接收调用bind返回的函数时传入的参数
thisArg.fn = fn
var params = [...params1, ...params2];
var result = thisArg.fn(...params)
delete thisArg.fn
return result
}
}