一、call()和apply()的语法、参数
1.call()方法调用一个函数,其具有一个指定的this值和分别地提供的参数(参数的列表)。
语法:fun.call(this.Arg, arg1, arg2, …)
参数:
thisArg:在fun函数运行时指定的this值。需要注意的是,指定的this值不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
arg1, arg2, …:指定的参数列表。
返回值:返回结果包括指定的this值和参数。
描述:可以让call()中的对象调用当前对象所拥有function。可以使用call()来实现继承:写一个方法,然后让另外一个新的对象来继承它(多个对象都有相同属性不用重复写)。
代码实例:
// 使用call方法调用父构造函数
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0) {
throw RangeError('Cannot create product' + this.name + ' with a negative price');
}
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
// 等同于
// function Food(name, price) {
// this.name = name;
// this.price = price;
// if (price < 0) {
// throw RangeError('Cannot create product' + this.name + ' with a negative price');
// }
//
// this.category = 'food';
// }
// function Toy 同上
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
console.log(cheese.category); // food
console.log(fun.category); // toy
2.apply()与call()方法相似,不同点在于提供参数的方式。apply使用参数数组而不是一组参数列表。
他的语法是:fun.apply(thisArg, [argsArray])
argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给fun函数。如果该参数的值为null或undefined,则表示不需要传入任何参数。
也可以使用 arguments 对象作为argsArray参数。arguments是一个函数的局部变量。它可以被用作被调用对象的所有未指定的参数。这样,在使用apply函数的时候就不需要知道被调用对象的所有参数。
代码实例:
// 定义一个学生类
function Person(name, age) {
this.name = name;
this.age = age;
}
// 定义一个学生类
function Student(name, age, grade) {
Person.apply(this, arguments);
this.grade = grade;
}
var student = new Student("Jasper" , 4 , "小班");
console.log("name: " + student.name + ", age: " + student.age + ", grade: " + student.grade);
// name: Jasper, age: 4, grade: 小班
二、在什么情况下分别使用call()和apply()
在给对象参数的情况下,如果参数的形式是数组的时候,比如apply示例里面传递了参数arguments,这个参数是数组类型,并且在调用Person的时候参数的列表是对应一致的(也就是Person和Student的参数列表前两位是一致的) 就可以采用 apply , 如果Person的参数列表是这样的(age,name),而Student的参数列表是(name,age,grade),这样就可以用call来实现了,也就是直接指定参数列表对应值的位置(Person.call(this,age,name,grade));
在参数较多且按顺序传递的时候,使用apply()方便一些,不需要把参数一个一个写上。
三、apply的巧妙用处
apply()可以将一个数组默认的转换为一个参数列表([param1,param2,param3] 转换为 param1,param2,param3) 。
1.Math.max 可以实现得到数组中最大的一项:
Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组 ,但是它支持Math.max(param1,param2,param3…),所以可以根据apply的这个特点来解决:
var max=Math.max.apply(null,array);
这样轻易的可以得到一个数组中最大的一项 。(这块在调用的时候第一个参数给了一个null,是因为没有对象去调用这个方法,只需要用这个方法来进行运算,得到返回的结果就可以,所以直接传递了一个null)
2.Math.min 可以实现得到数组中最小的一项:
var min=Math.min.apply(null,array);
3.Array.prototype.push 可以实现两个数组合并:
同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN),所以同样也可以通过apply来装换一下这个数组,即:
var arr1 = new Array("1","2","3");
var arr2 = new Array("4","5","6");
Array.prototype.push.apply(arr1,arr2);
也可以这样理解,arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合.
通常在什么情况下,可以使用apply类似Math.min等之类的特殊用法:
一般在目标函数只需要n个参数列表,而不接收一个数组的形式,可以通过apply的方式巧妙地解决问题!
参考文档:
MDN call()方法