在JavaScript中,有這麼倆貨,一個叫call,一個叫apply,它們倆工做幾乎一毛同樣,可是也有所區別,曾經對這個知識點很是困惑,看過幾篇博客也沒搞清楚這哥倆到底打算要幹個啥,直到某天仔細研究過
this
關鍵詞的相關知識點後,才恍然大悟,
這篇文章主要就是爲call
和apply
兄弟倆寫「人物傳記」,但願能幫助到其餘對這個問題有困惑的童鞋。segmentfault
在正式介紹這哥倆以前,首先咱們得知道兄弟二人究竟是誰家的熊孩子,因此有必要熟悉一下哥倆的「家族世系」,刨根問底,以便往後開心地與兄弟二人愉快地玩耍交朋友。call
和apply
是被定義到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
。此時由於沒有其餘參數要傳入,因此本例中使用call
和apply
的輸出結果是沒有區別的。
他們區別在於傳遞參數的方式: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
關鍵詞的知識,請閱讀這篇文章函數
call
與apply
方法使用的一個最多見的場景就是在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();
須要注意的一點是,使用call
和apply
方法不能繼承原型鏈,若是要實現原型鏈繼承,則須要混合使用子類原型對象指向父類的實例的方式實現繼承。具體可參考下面代碼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"
總結一下call
與apply
prototype
兄弟倆的任務:
使用一個指定的this值和若干個指定的參數值的前提下調用某個函數或方法。code
區別:call
方法接受的是若干個參數的列表,參數之間以逗號分隔 而apply
方法接受的是一個包含多個參數的數組或者僞數組(好比arguments)。對象
本篇人物小傳自此結束。