JavaScript中的apply()和call()

刚接触 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 方法 详解

你可能感兴趣的:(JavaScript中的apply()和call())