逆向调用apply和call

逆向调用apply和call

apply 和 call 方法都可以理解为 function 对象中的隐藏方法,其实它们是 Function 对象的 prototype 属性对象中的方法,而 function 对象是 Function 的实例对象,因此 function 可以调用 Function 的 prototype 属性对象中的这两个方法。
这两个方法的作用相同,都用于逆向调用。正常的方法调用是通过“对象,方法名(参数)”结构调用的,也就是需要使用对象来调用相应的方法。但是,使用这两个方法正好反过来,它们都可以实现用方法来调用对象,也就是将一个对象传递给方法,然后该方法就可以作为对象的方法来调用,这样就不需要先将方法添加为对象的属性,然后再调用了,例如下面的例子。

1
2
3
4
5
6
var obj = { v: 237 };
function logV() {
console.log(this.v)
};
logV.apply(obj); //237
logV.call(obj); //237

这个例子中的 obj 对象并没有 logV 方法,但是通过 logV 方法的 apply 和 call 属性方法调用 obj 对象就可以实现跟将 logV 方法设置为 obj 对象的属性然后再调用相同的效果。方法在调用时还可能需要传递参数,使用 apply 和 call 来调用也可以传递参数,但这两个方法传递参数的方式不一样,这也是它们唯一的区别。使用 apply 调用时参数需要作为一个数纽传递,而使用 call 调用时参数直接按顺序传入即可,调用语法分别如下。

1
2
fun.apply(thisArg , [argsArray]); 
fun.call(thisArg [,argl [ ,arg2 [ , ...]]]);

它们的第一参数都是 this 对象,也就是调用方法的对象,后面的参数都是传递给方法的参数。我们来看个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function sell(goods, num) {
return this.price.get(goods) * num;
}
var tmall = {
price: new Map([
["iphone6_Plus_16g", 5628],
["iphone6_Plus_64g", 6448],
["小米 Note 顶配版", 2999]
])
}
var jd = {
price: new Map([
["iphone6_Plus_16g", 5688],
["iphone6_Plus_64g", 6423],
["小米 Note 顶配版", 2999]
])
}
console.log(sell.apply(jd, ["iphone6_Plus_64g", 1]));//6423
console.log(sell.call(jd, "iphone6_Plus_64g", 1));//6423
console.log(sell.apply(jd, ["小米 Note 顶配版",2]));//5998
console.log(sell.call(tmall, "iphone6_Plus_16g", 3)); //16884

在这个例子中,我们首先定义了一个 sell 方法,用于计算价格,它有两个参数,分别表示商品名和数量,计算时需要先从当前对象的 price 属性中获取羊价,再来以数量。然后,我们定义了两个对象 tmall 和 jd ,它们都只包含一个 price 属性,它是 Map 类型用于表示不同商域中商品的单价。最后,我们使用 sell 方法的 apply 和 call 分别调用 tmall 和 jd 对象计算了各自的价格。如果还需要计算其他平台(对象)的价格,只需要创建相应的对象就可以了,而不需要将 sell 方法分别添加到它们的属性中。