今天看原生js的时候看到了callapply,对这两个方法印象不是很清楚,只记得这两个方法很相似,作用大概是让A通过callapply能够调用B独有的方法,但是具体的使用方法已经模糊,所以网上查了资料重新理了一遍。

先看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Createpeople(name, age) {
this.name = name;
this.age = age;
}
Createpeople.prototype.say = function() {
console.log('Hello!My name is ' + this.name);
}

var Amy = new Createpeople('Amy', 18);
Amy.say(); //Hello!My name is Amy

var john = {
name: 'john',
age: 20
}
john.say(); //john.say is not a function
Amy.say.call(john); //Hello!My name is john
Amy.say.apply(john); //Hello!My name is john

Createpeople是一个构造函数,并且在原型中写入了一个say方法。我们用Createpeople创造了Amy对象,所以Amy理所当然地可以调用say方法。而john是我们手动创建的一个对象,所以john调用say方法理所应当会报错。那么如何让john能够调用say方法呢?那就要通过call方法或apply方法了。通过Amy.say.call(john),从输出结果来看john正确的调用了say方法,apply也同样。

为什么呢?原因就在于callapply在调用的时候会传入一个调用对象,即this,它们能将原来不指向传入对象的函数的this强行指向传入对象。可能这样说不是很明白,下面我来解释一下:

在其他方法执行的时候会默认传入一个调用对象,比如在Amy调用say方法的时候,默认传入的调用对象为Amysay方法作为Amy的一部分正常情况下因为正常情况下this只能指向Amy,但是通过callapply方法能让say方法的this强行指向传入的johnthis变成了john,理所当然,say方法就能正常执行了。

那么callapply有什么区别呢?

区别在于参数的传入方式不同。
举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
function add(a, b) {
return console.log(a + b);
}

function sub(c, d) {
return console.log(c - d);
}

sub.apply(add, [2, 3]); //-1
sub.call(add, 2, 3); //-1
add.apply(sub, [1, 2]); //3
add.call(sub, 1, 2); //3

call方法参数是一个一个传的,而apply方法,除了this,其他参数是用数组的方式传的。
由于apply传数组这个特点,我们可以很方便地对数组进行某些操作,比如拼接两个数组:

1
2
3
4
var list1 = [1, 2, 3];
var list2 = [4, 5, 6];
[].push.apply(list1, list2); //6
console.log(list1); //[1, 2, 3, 4, 5, 6]

push方法可以传很多参数,但是不能传数组,正常情况下凭借数组只能够通过循环一个一个添加,但是apply正好需要把多个传入的参数打包成数组,所以正好满足了条件。