每天一点点--call、bind、apply的用法与区别

203 阅读2分钟

1、call、bind、apply 都是用来干什么的?

call、bind、apply都是用来改变this指向的

2、他们之间的区别是什么?

2.1 call方法

可以指定该函数内部this的指向,然后在所指定的作用域中,调用该函数,并且会立即执行该函数。
call的使用方法:

function keith(a, b) {
    return a+b;
}
keith.call(null, 1 , 2); // 3

call有两个参数,第一个参数必需,用来制定this指向,第二个是函数调用时需要传递的参数,必需一个个的添加。
call的执行过程:
1、把找到的call方法执行,当call方法执行的时候,内部处理了一些事情
2、首先把要操作的函数中的this关键字变为call方法第一个传递的实参
3、把call方法第二个及之后的实参获取到
4、把要操作的函数执行,并且把第二个以后传递进来的实参传递给函数

var keith = {
    rascal: 123
};
  
var rascal = 456;

function a() {
    console.log(this.rascal);
}
 
a(); //456
a.call(); //456
a.call(null); //456
a.call(undefined); //456
a.call(this); //456
a.call(keith); //123

a函数中的this关键字,如果指向全局对象,返回结果为456。可以看到,如果call方法没有参数,或者参数为null或undefined或者this,则等同于指向全局对象。如果使用call方法将this关键字指向keith对象,也就是将该函数执行时所在的作用域为keith对象,返回结果为123。

2.2 apply方法

apply与call唯一不同的一点是:第二个参数必须以数组的形式添加

function keith(a, b) {
    return a+b;
}
keith.call(null, 1 , 2); // 3
keith.apply(null, [1,2]); // 3

2.3 bind方法

bind与call不同的一点是:bind改变this指向,并返回一个新函数,bind方法不会立即执行。

var keith = {
    a: 1,
    count: function() {
        console.log(this.a++);
    }
};

keith.count(); //1
keith.count(); //2
keith.count(); //3

上面的例子中,this.a指向的是keith,所以每调用一次,a的值都会+1;但如果把keith.count赋值给另外一个变量时,调用就会出错,例如:

var keith = {
    a: 1,
    count: function() {
        console.log(this.a++);
    }
};
f = keith.count;
f(); // NaN

这个例子中,keith.count赋值给f,那么this指向的不再死Keith了,而是window对象,window.a是undefined,undefined++就会变成NaN。 为了解决这个问题,可以使用bind方法,将keith对象里的this绑定到keith对象上,或者是直接调用。

var f = keith.count.bind(keith);
f(); //1
f(); //2
f(); //3
或者绑定到别的对象上:
var obj = {
    a: 100
};
var f = keith.count.bind(obj);
f(); //100
f(); //101
f(); //102

综上:

function keith(a, b) {
    return a + b;
}
console.log(keith.apply(null,[1,4])); //5
console.log(keith.call(null,1,4)); //5
console.log(keith.bind(null, 1, 4)); //keith()
console.log(keith.bind(null, 1, 4)()); //5

可以看出call,apply,bind三者的区别:call和apply方法都是在调用之后立即执行的。而bind调用之后是返回原函数,需要再调用一次才行。call和bind的参数是一个个添加进去,而apply是使用数组一次性添加