【JavaScript】call與apply兄弟列傳

在JavaScript中,有這麼倆貨,一個叫call,一個叫apply,它們倆工做幾乎一毛同樣,可是也有所區別,曾經對這個知識點很是困惑,看過幾篇博客也沒搞清楚這哥倆到底打算要幹個啥,直到某天仔細研究過this關鍵詞的相關知識點後,才恍然大悟,
恍然大悟
這篇文章主要就是爲callapply兄弟倆寫「人物傳記」,但願能幫助到其餘對這個問題有困惑的童鞋。segmentfault

家族世系

在正式介紹這哥倆以前,首先咱們得知道兄弟二人究竟是誰家的熊孩子,因此有必要熟悉一下哥倆的「家族世系」,刨根問底,以便往後開心地與兄弟二人愉快地玩耍交朋友。
callapply是被定義到Function.prototype上的兩個方法,也就是Function類型中的原生方法,早在ECMAScript標準的第一個版本中就已經被初步定義,歷史悠久,因此現代瀏覽器幾乎都支持,徹底沒必要擔憂兼容性。數組

基本用法

call方法與apply方法要實現的功能幾乎一致,就是使用一個指定的this值和若干個指定的參數值的前提下調用某個函數或方法。 二者只有一個區別,call方法接受的是若干個參數的列表,參數之間以逗號分隔apply方法接受的是一個包含多個參數的數組或者僞數組(好比arguments)
思考如下代碼:瀏覽器

var objA = {
  x:"value is A",
  getX:function () {
    console.log(this.x);
  }
};

var objB={
  x:"value is B",
  getX:function () {
    console.log(this.x);
  }
};

objA.getX(); //"value is A"
objA.getX.call(objB);//"value is B",this被從新綁定到了objB上

上面的代碼很簡單,當objA.getX()被直接調用執行的時候,this理所應當地指向了objA對象,可是當objA.getX.call(objB)被調用執行時,objA.getX中的this被改變,指向了objB。此時由於沒有其餘參數要傳入,因此本例中使用callapply的輸出結果是沒有區別的。
他們區別在於傳遞參數的方式:app

var objA = {
  x: 'A',
  getX: function (val1, val2) {
    console.log(val1 + val2 + this.x);
  }
};
var objB = {
  x: 'B',
  getX: function (val1, val2) {
    console.log(val1 + val2 + this.x);
  }
};
objA.getX.call(objB, 'value', 'is'); //"value is B"
objA.getX.apply(objB, ['value','is']); //"value is B"

PS:若想了解更多關於this關鍵詞的知識,請閱讀這篇文章函數

用做類的繼承

callapply方法使用的一個最多見的場景就是在js類的繼承中使用,廢話很少說,直接上代碼:this

var Person = function (name, age) {
  this.name = name;
  this.age = age;
  this.sayAge = function () {
    console.log('Age:' + this.age);
  };
}
var Worker = function (name, age, workerId) {
  this.workerId = workerId;
  Person.apply(this, arguments); //apply的第二個參數也能夠是僞數組
  this.showId = function () {
    console.log(this.workerId);
  }
}
var worker = new Worker('張三', 22, '521608');
worker.sayAge();

須要注意的一點是,使用callapply方法不能繼承原型鏈,若是要實現原型鏈繼承,則須要混合使用子類原型對象指向父類的實例的方式實現繼承。具體可參考下面代碼spa

var Person = function (name,age) {
  this.name = name;
  this.age = age;
  this.sayAge = function () {
      console.log("Age:"+this.age);
  };
}
//定義到原型鏈上的方法
Person.prototype.sayName = function () {
    console.log("Name:"+this.name);
};
var Worker = function (name,age,workerId) {
  this.workerId= workerId;
  Person.apply(this,arguments);//這裏沒有繼承父類prototype中的方法
}
Worker.prototype = new Person(this.name,this.age);

Worker.prototype.showId = function () {
    console.log("ID:",this.workerId);
};

var worker = new Worker("張三",22,"521608");
worker.sayAge(); //"Age:22"
worker.sayName();//"Name:張三"
worker.showId();//"ID: 521608"

太史公曰

總結一下callapplyprototype

  • 兄弟倆的任務:
    使用一個指定的this值和若干個指定的參數值的前提下調用某個函數或方法。code

  • 區別:
    call方法接受的是若干個參數的列表,參數之間以逗號分隔apply方法接受的是一個包含多個參數的數組或者僞數組(好比arguments)對象

本篇人物小傳自此結束。

相關文章
相關標籤/搜索