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