三者区别:
- (都是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的封装
// 封装一个myCallFunction.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);// 同理,封装一个myApplyFunction.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);
