首頁  >  文章  >  web前端  >  Javascript中call和apply函數的比較和使用實例_javascript技巧

Javascript中call和apply函數的比較和使用實例_javascript技巧

WBOY
WBOY原創
2016-05-16 16:16:001031瀏覽

一些簡單的Javascript操作中較少會用到call和apply函數,在另外一些較大型的操作中,如web應用開發,js框架開發中可能會經常遇到這兩個函數。關於這兩個函數的解釋,網路上的資料也很多,但是本人認為很多資料不是照本宣科,就是高度雷同,缺少接地氣的解釋。接下來我試著用更清晰簡單的思路來分析解釋這兩個函數。

複製程式碼 程式碼如下:

我們可以將call()和apply()看做是某個物件的方法,透過呼叫方法的實行來間接呼叫函數。 call()和apply()的第一個實參是要呼叫函數的母對象,它是呼叫上下文,在函數體內透過this來獲得對它的參考。要對物件o的方法來呼叫函數f(), 可以這樣使用call()和apply(): f.call(o) f.apply(o).[1]

先來分析一下call,這裡有ECMAScript 3rd Edition對call函數的解釋[2]:當call方法被一個function物件呼叫時(func.call(0)),需要傳入一個必須的參數和若干個非必須的參數,它的執行過程是這樣的:
a, 如果呼叫call的物件是不可運作的,拋出一個TypeError錯誤。
b, 設定參數清單為空
c, 如果被呼叫的方法傳入不只一個參數,那麼依序把arg1,arg2…插入參數列表裡
d, 回傳呼叫call的函數結果,把呼叫函數(func)中的this用傳入的參數1替換,把傳入的參數列表當作這個函數的參數。
實際上,call函數是function物件的原型,也就是說,當呼叫call的函數必須也是個函數,當呼叫這個call時,把呼叫call的函數中的this用傳入的物件替換就行了。下面有個例子:

<script>
 function C1(){
 this.name='张三';
 this.age='24';
 this.sayname=function(){
  console.log("这里是C1类,我的名字是:"+this.name+"我的年龄是"+this.age);
 }
 }
 function C2(){
 this.name='李四';
 this.age='25';
 }
 var c1=new C1();
 var c2=new C2();
 c1.sayname();
 c1.sayname.call(c2);
</script>

執行結果:
這裡是C1類,我的名字是:張三我的年齡是24
這裡是C1類,我的名字是:李四我的年齡是25
上面的程式碼中,宣告了兩個類,C1和C2,C1有兩個屬性,一個方法,C2也有兩個和C1一樣的屬性,實例化之後,c1.sayname()印出了實際屬性,c1 .sayname.call(c2)卻印出除了c2的屬性,為什麼為這樣?因為sayname()是個函數,而且函數體內有this,當call執行的之後,this就會被c2代替,所以,最後會印出c2的屬性。
apply和call的差別就在於可選參數的傳遞,apply的可選參數全部存放在一個數組當中,當成一個參數竄入而call是分成多個參數傳入。
那麼,apply和call函數有哪些應用呢?第一個是網路上比較經典的求數字數組中的最大元素,直接用Math.max.apply(null,array)即可,另外一個是可以用apply和call實現繼承,如下:

<script> 
 function Human(name,sex){
 this.name=name;
 this.sex=sex;
 this.walk=function(){
  console.log('我在走路');
 }
 }
 function Child(){
 Human.call(this,"小明","男")
 this.paly=function(){
  console.log('我很喜欢玩耍');
 }
 this.intruduce=function(){
  console.log('大家好,我是'+this.name);
 }
 }
 var jinp=new Human('Jack','男');
 var xiaoping=new Child();
 xiaoping.walk();
 xiaoping.paly();
 xiaoping.intruduce();
</script>

執行結果:
我在走路
我很喜歡玩耍
大家好,我是小明
與call()和apply()相似的函數是bind(), 它是在ECMAScript 5中新增的方法,但在ECMAScript 3中可以輕易的模擬bind()。 bind函數一樣也是Javascript中Function.prototype的方法,這個方法的主要內容是將函數綁定到某個物件。當函數f()上綁定bind()方法並傳入一個物件o作為參數,這個方法將會傳回一個新的函數當作o的方法來呼叫。傳入新函數的任何實參都會傳入原始函數。如下:

<script>
 function introduce(country,hobby){
 return "大家好,我叫"+this.name+", 今年"+this.age+"岁, 来自"+country+", 喜欢"+hobby;
 }
 var xiaoming={name:"小明",age:20}
 var jieshao=introduce.bind(xiaoming);
 console.log(jieshao("中国","打球"));
</script>

執行結果:
大家好,我叫小明, 今年20歲, 來自中國, 喜歡打球
上面的範例等效於:

<script>
 function introduce(country,hobby){
 return "大家好,我叫"+this.name+", 今年"+this.age+"岁, 来自"+country+", 喜欢"+hobby;
 }
 var xiaoming={name:"小明",age:20}
 console.log(introduce.apply(xiaoming,["中国","打球"]));
    //或者下面这个
 console.log(introduce.call(xiaoming,"中国","打球"));
</script>

要注意的是:在ECMAScript 5的嚴格模式中,call()和apply()的第一個實參都會變成this的值,即使傳入的實參是原始值甚至是null或者undefined 。在ECMAScript 3和非嚴格模式中,傳入的null和undefined都會被全域對戲那個代替,而其他原始值會被對應的包裝物件所替代。

參考資料

[1], Javascript權威指南第6版,189頁
[2], Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )
[3], Function.prototype.apply (thisArg, argArray)

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn