作为业务的前端开发,有时候看一些代码的时候碰到apply和call方法会觉得很纳闷,好好的一个函数执行,非要写成这样,看了网上的一些事例代码还是没真正理解其不得不用的场景。直到最近自己碰到一个不得不用apply方法的场景,才真正理解了apply和call的作用。
直接看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<html> <body> <script> var product = "house"; var boss = { chooseWorker: function(makeFunction){ return makeFunction(2); }, make: function(count){ // 为了与foodWorker和carWorker的make方法做对比 console.log("boss does not work"); } }; var foodWorker = { product : "food", make: function(count){ console.log("foodWorker: make " + count + " " + this.product); } }; var carWorker = { product : "car", make: function(count){ console.log("carWorker: make " + count + " " + this.product); } }; boss.chooseWorker(foodWorker.make); boss.chooseWorker(carWorker.make); </script> <body> </html> |
在这段代码里面,我达到的目的是:通过传递worker对象的make方法的方式来让boss选择生产出那种产品,boss的chooseWorker方法的参数是make方法。我本来期望传给chooseWorker方法的参数如果是foodWorker的make方法就生产food,如果是carWorker的make方法就生产carWorker。期望的结果是这样:
1 2 |
foodWorker: make 2 food carWorker: make 2 car |
但是结果并不是这样,而是:
1 2 |
foodWorker: make 2 house carWorker: make 2 house |
那为什么我传递的是指定对象的方法,里面的this.product确实“house”呢?
原因是JavaScript对象的函数本身并不包含对象的信息的信息,如果直接调用makeFunction,其调用方默认是window对象,也就是说this==window,所以this.product就是“house”了。要想达到预想的效果,就得用到apply方法了。比如这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<html> <body> <script> var product = "house"; var boss = { chooseWorker: function(makeFunction, worker){ return makeFunction.apply(worker, [2]); }, make: function(count){ console.log("boss does not work"); } }; var foodWorker = { product : "food", make: function(count){ console.log("foodWorker: make " + count + " " + this.product); } }; var carWorker = { product : "car", make: function(count){ console.log("carWorker: make " + count + " " + this.product); } }; boss.chooseWorker(foodWorker.make, foodWorker); boss.chooseWorker(carWorker.make, carWorker); </script> <body> </html> |
其输出结果就打到预期了,对于一些设计模式和继承使用的时候,apply和call会常被使用到。主要是解决this对象的指向问题,当然也可以通过使用apply和call来替换方法的调用者。
apply和call的作用基本相同,唯一的区别是apply有两个参数,而call只有一个参数。
- apply的第一个参数是函数的调用对象,第二个参数是函数的参数列表(参数数组),上面的代码就是个例子。当然如果函数没有参数,可以给apply方法传空数组([]);
- call的参数只有一个,就是函数的调用对象。
apply包含了call的功能,所以一般用apply就行了。这是我目前的理解,抛砖引玉。