call apply bind三者均可以改變this指向
call
和
apply
都可以動态改變
this
的指向。作用都是相同的,隻是傳參的方式不同。
除了第一個參數外,
call
可以接收一個參數清單,
apply
隻接受一個參數數組。
bind将函數綁定到某個對象,bind()會建立一個函數,函數體内的this對象的值會被綁定到傳入bind()中的第一個參數的值
下面涉及很多對僞數組arguments的操作,不能直接使用數組的方法
下面三種方法對取第二個之後的參數是等效的

call
整體思路:将函數或者方法添加在對象上,那麼該對象就可以調用該函數了,但是要調用結束後删除掉該函數。
- 獲得對象,當沒有傳遞參數時候,為window(特殊情況處理)
- 給對象添加方法,方法指派為該函數(this擷取)
- 獲得第二個之後的參數作為執行的參數
- 執行該對象的方法(傳參)獲得結果
- 删除對象的方法
- 傳回結果
Function.prototype.mycall=function(context){
var context=context||window;
context.fn=this;//目前調用call的函數作為對象的方法
var args=[...arguments].slice(1);
var res=context.fn(...args);
delete context.fn;
return res;
}
驗證:
var a=2;
var obj={a:1}
function say(b,c) {
console.log(this.a)
console.log(b+c)
}
say(4,3);//2,7
say.mycall(obj,1,1)//1 2
apply
思路:與call類似,對于傳入參數進行判斷,如果存在第二個參數(數組),展開數組傳入函數執行
- 獲得對象,當沒有傳遞參數時候,為window(特殊情況處理)
- 給對象添加方法,方法指派為該函數(this擷取)
- 判斷是否存在第二個參數(數組)存在,執行該對象的方法(傳參)獲得結果; 不存在,執行該對象的方法(不傳參)獲得結果
- 删除對象的方法
- 傳回結果
Function.prototype.myapply=function(context){
var context=context||window;
context.fn=this;
var res;
if(arguments[1]){//存在第二個參數
res=context.fn(...arguments[1]);
}else{不存在第二個參數
res=context.fn();
}
delete context.fn;
return res;
}
驗證
var a=2;
var obj={a:1}
function say(b,c) {
console.log(this.a)
console.log(b+c)
}
say(4,3);//2,7
say.myapply(obj,[1,1])//1 2
bind
傳回一個函數,使用apply方法
Function.prototype.mybind=function (context) {
if (typeof this!=='function') {//調用bind的一定要是函數,傳回綁定this後的函數,否則報錯
throw new Error(this+'is not a function')
}
var self=this;//儲存調用bind的函數
// var context=[].shift.call(arguments);
// var context=Array.prototype.shift.call(arguments);
//如果沒有傳入參數,通過arguments獲得綁定的this上下文
var args=[].slice.call(arguments,1);//擷取綁定this時候傳入的參數,與調用時的參數區分開
// var args=Array.prototype.slice.call(arguments,1);//與上面一行等效
var fbound=function () {
var bindArgs=[...arguments];
// 如果是構造函數,this為構造函數的執行個體,上下文仍為新建立的對象,不修改為context
self.apply(this instanceof self ? this:context, args.concat(bindArgs));
}
//傳回的函數的原型鍊要和調用bind的函數原型鍊相同
fbound.prototype=Object.create(self.prototype);
return fbound;
}
驗證
function bar(){
var sum=0;
var arr=[...arguments];
for (var i = 0; i < arr.length; i++) {
sum+=arr[i];
}
console.log(this);
console.log(sum)
}
var foob=bar.mybind({a:1},3);
bar(1,2);//window 3
foob(4)//{a:1} 7