刚接触 apply() 的时候总是模棱两可,似懂非懂,公司的前辈说这个方法就是为了改变函数的 this 。具体到底是如何改变,在什么场景下改变呢?来好好梳理一下吧~
(一)语法:
Function.prototype.apply()
fun.apply(thisArg, [argsArray])
thisArg: 在fun函数运行时指定的this值,即这个参数将替换 fun 里面的 this 对象。
[argsArray]: 这个参数是一个数组,将作为参数传给 fun。很神奇的是,它虽然是数组格式,但却会先默默转换成列表格式,再传参给 fun 。
Function.prototype.call()
fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg: 在fun函数运行时指定的this值,这个参数将替换 fun 里面的 this 对象。
arg1, arg2, ...:传给 fun 函数的参数列表。
(二)两者的区别:
call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。
(三)看几个常用的使用场景:
示例一:
在调用方法的时候使用,改变 this 对象。
function Cat(){
}
Cat.prototype={
food:"fish",
say: function(){
console.log("I love "+this.food);
}
}
var blackCat = new Cat;
blackCat.say(); // say方法里面的this是Cat()
function Dog(){
}
Dog.prototype={
food:"bone"
}
var blackDog = new Dog;
blackCat.say.apply(blackDog); // I love bone ,相当于在这执行了blackCat.say(),但是say方法里面的this被改变,变成了dog()
示例二:
在函数内部使用, 调用其它对象的方法给自己使用,经常会传到参数。
function Person(name, age){
this.name=name;
this.age=age;
}
function Student(name, age, grade){
Person.apply(this,arguments); // 相当于在这执行了Person(),只是Person里面的this变成了Student,arguments将作为参数传给Person
// call的写法
// Person.call(this, name, age);
this.grade=grade;
}
var student=new Student("zhangsan",21,"一年级");
console.log("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
// name:zhangsan
// age:21
// grade:一年级
示例三:
在一个异步的函数中用于引入一个回调函数。
function aFun(cate, callback) {
var self = this;
$.ajax(url)
.done(function(){
if (cate == 'success') {
callback.call(self, arg); //在这里执行 callback,arg 是传给 callback 的参数
}
})
.fail(function(){
if (cate == 'failure') {
callback.call(self, arg);
}
})
}
aFun('success', function(arg) {
console.log('成功啦~')
})
aFun('failure', function(arg) {
console.log('失败了。。。')
})
(四)apply() 的妙用
利用了“apply的第二个参数值,是一个数组,可以自动转换为一个参数列表”这一特性。
求一个数组中的最大值/最小值
var num = [10, 0, 3, 15];
console.log( Math.max(10, 0, 3, 15)); // Math.max方法的参数仅支持列表形式
console.log( Math.max.apply(null, num)); //第一个参数用null,因为没有对象去调用这个方法,只需要把num作为参数传入Math.max()方法,并得到返回的结果
合并两个数组
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2); // Array.prototype.push() 方法的参数仅支持列表形式
console.log(arr1); // [1, 2, 3, 4, 5, 6]
console.log(arr2); // [4, 5, 6]
(五)什么时候用 apply(),什么时候用call()
综上所述我们可以总结下这两个方法的使用场景:
- 如果只有一个参数时,用哪个方法都是一样的。
- 如果被调用的函数参数只支持列表形式,而现有的参数是数组形式,可以用apply() 巧妙的转换。
- 使用 apply() 时,要注意参数数组里的顺序是否对得上,如果现有参数的顺序不是要求的,这时候用 call() 指定参数传入的顺序。例如:
function Person(name, age){
this.name=name;
this.age=age;
}
function Student(age, name, grade){
Person.apply(this,arguments); // 如果这时候用这种写法就会出错,
Person.call(this, name, age); // 这时候用call,可以指定参数传入的顺序
this.grade=grade;
}
本文参考文章有:
Js apply 方法 详解