三者区别:
- (都是es5的api),apply与call都是 执行函数的同时,改变函数的this指向。区别在于它们的参数方式不同: ```javascript //案例1 第一个参数是一致的 const obj = { a:()=>{console.log(this)}, //绑定到了外部环境 即window b:function(){console.log(this)} //取决于执行环境 } obj.b() // 打印 obj 对象 <=> 由obj调用 const calledObj = {a:1} obj.b.call(calledObj); // 第一个参数即改变后的this指向 <=> 打印calledObj obj.b.apply(window); // 同上 <=> 打印window
// 案例2 后面参数是不同形式的 function fo(a,b,c){ console.log(this) console.log(a,b,c) } fo(1,2,3); //打印window 1,2,3 fo.call(calledObj,1,2,3); 打印calledObj,1,2,3 fo.apply(calledObj,[1,2,3]);
- bind不会改变原函数的this指向,但会返回一个新的函数,新的函数绑定了this指向;
```javascript
// 案例
function fo2(prop){
console.log(this);
console.log(prop);
}
const calledObj2 = {a:1}
fo2(2) ; // 打印window , 2;
const newFo = fo2.bind(calledObj2); // 返回了一个新的函数哟
newFo(3); // 打印calledObj2, 3;
call,apply,bind的封装
// 封装一个myCall
Function.prototype.myCall = function(...args){
const [context,...others] = args;
context.fn = this; // 这个this指向Function的实例对象,也就是那个函数
const result = context.fn(...others);
delete context.fn; // 别忘记干掉这个属性
console.log(context);
return result;
}
// 试一试
function fo(a,b,c){
console.log(this,a,b,c);
}
const calledObj = {a:1}
fo.myCall(calledObj,1,2,3);
// 同理,封装一个myApply
Function.prototype.myApply = function(context,args){
context.fn = this;
const result = context.fn(...args);
delete context.fn; // 别忘记干掉这个属性
return result;
}
// 试一试
fo.myApply(calledObj,[1,2,3])
// 那么再封装一个myBind,暂不考虑new的场景
Function.prototype.myBind = function(context=window){
const _this = this;
const newFn = function(...args){
return _this.apply(context,args);
};
return newFn;
}
// 试一试
const newFo = fo.myBind(calledObj);
newFo(1,2,3);