Javascript中call和apply函數(shù)的比較和使用實(shí)例
一些簡(jiǎn)單的Javascript操作中較少會(huì)用到call和apply函數(shù),在另外一些較大型的操作中,如web應(yīng)用開(kāi)發(fā),js框架開(kāi)發(fā)中可能會(huì)經(jīng)常遇到這兩個(gè)函數(shù)。關(guān)于這兩個(gè)函數(shù)的解釋,網(wǎng)上的資料也很多,但是本人認(rèn)為很多資料要么照本宣科,要么高度雷同,缺少接地氣的解釋。接下來(lái)我試圖用更加清晰簡(jiǎn)單的思路來(lái)分析解釋這兩個(gè)函數(shù)。
我們可以將call()和apply()看做是某個(gè)對(duì)象的方法,通過(guò)調(diào)用方法的實(shí)行來(lái)間接調(diào)用函數(shù)。call()和apply()的第一個(gè)實(shí)參是要調(diào)用函數(shù)的母對(duì)象,它是調(diào)用上下文,在函數(shù)體內(nèi)通過(guò)this來(lái)獲得對(duì)它的引用。要想對(duì)對(duì)象o的方法來(lái)調(diào)用函數(shù)f(), 可以這樣使用call()和apply(): f.call(o) f.apply(o).[1]
先來(lái)分析一下call,這里有ECMAScript 3rd Edition對(duì)call函數(shù)的解釋[2]:當(dāng)call方法被一個(gè)function對(duì)象調(diào)用時(shí)(func.call(0)),需要傳入一個(gè)必須的參數(shù)和若干個(gè)非必須的參數(shù),它的執(zhí)行過(guò)程是這樣的:
a, 如果調(diào)用call的對(duì)象是不可運(yùn)行的,拋出一個(gè)TypeError錯(cuò)誤。
b, 設(shè)置參數(shù)列表為空
c, 如果被調(diào)用的方法傳入不止一個(gè)參數(shù),那么依次把a(bǔ)rg1,arg2…插入到參數(shù)列表里
d, 返回調(diào)用call的函數(shù)結(jié)果,把調(diào)用函數(shù)(func)中的this用傳入的參數(shù)1替換,把傳入的參數(shù)列表當(dāng)作這個(gè)函數(shù)的參數(shù)。
實(shí)際上,call函數(shù)是function對(duì)象的原型,也就是說(shuō),當(dāng)調(diào)用call的函數(shù)必須也是個(gè)函數(shù),當(dāng)調(diào)用這個(gè)call時(shí),把調(diào)用call的函數(shù)中的this用傳入的對(duì)象替換就行了。下面有個(gè)例子:
<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>
執(zhí)行結(jié)果:
這里是C1類,我的名字是:張三我的年齡是24
這里是C1類,我的名字是:李四我的年齡是25
上面的代碼中,聲明了兩個(gè)類,C1和C2,C1有兩個(gè)屬性,一個(gè)方法,C2也有兩個(gè)和C1一樣的屬性,實(shí)例化之后,c1.sayname()打印出了實(shí)際屬性,c1.sayname.call(c2)卻打印除了c2的屬性,為什么為這樣?因?yàn)閟ayname()是個(gè)函數(shù),并且函數(shù)體內(nèi)有this,當(dāng)call執(zhí)行的之后,this就會(huì)被c2代替,所以,最終會(huì)打印出c2的屬性。
apply和call的區(qū)別就在于可選參數(shù)的傳遞,apply的可選參數(shù)全部存放在一個(gè)數(shù)組當(dāng)中,當(dāng)成一個(gè)參數(shù)竄入而call是分成多個(gè)參數(shù)傳入。
那么,apply和call函數(shù)有哪些應(yīng)用呢?第一個(gè)是網(wǎng)絡(luò)上比較經(jīng)典的求數(shù)字?jǐn)?shù)組中的最大元素,直接用Math.max.apply(null,array)即可,另外一個(gè)是可以用apply和call實(shí)現(xiàn)繼承,如下:
<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>
執(zhí)行結(jié)果:
我在走路
我很喜歡玩耍
大家好,我是小明
與call()和apply()相似的函數(shù)是bind(), 它是在ECMAScript 5中新增的方法,但在ECMAScript 3中可以輕易的模擬bind()。bind函數(shù)一樣也是Javascript中Function.prototype的方法,這個(gè)方法的主要內(nèi)容是將函數(shù)綁定至某個(gè)對(duì)象。當(dāng)函數(shù)f()上綁定bind()方法并傳入一個(gè)對(duì)象o作為參數(shù),這個(gè)方法將返回一個(gè)新的函數(shù)當(dāng)作o的方法來(lái)調(diào)用。傳入新函數(shù)的任何實(shí)參都將傳入原始函數(shù)。如下:
<script>
function introduce(country,hobby){
return "大家好,我叫"+this.name+", 今年"+this.age+"歲, 來(lái)自"+country+", 喜歡"+hobby;
}
var xiaoming={name:"小明",age:20}
var jieshao=introduce.bind(xiaoming);
console.log(jieshao("中國(guó)","打球"));
</script>
執(zhí)行結(jié)果:
大家好,我叫小明, 今年20歲, 來(lái)自中國(guó), 喜歡打球
上面的例子等效于:
<script>
function introduce(country,hobby){
return "大家好,我叫"+this.name+", 今年"+this.age+"歲, 來(lái)自"+country+", 喜歡"+hobby;
}
var xiaoming={name:"小明",age:20}
console.log(introduce.apply(xiaoming,["中國(guó)","打球"]));
//或者下面這個(gè)
console.log(introduce.call(xiaoming,"中國(guó)","打球"));
</script>
需要注意的是:在ECMAScript 5的嚴(yán)格模式中,call()和apply()的第一個(gè)實(shí)參都會(huì)變成this的值,哪怕傳入的實(shí)參是原始值甚至是null或者undefined。在ECMAScript 3和非嚴(yán)格模式中,傳入的null和undefined都會(huì)被全局對(duì)戲那個(gè)代替,而其他原始值會(huì)被相應(yīng)的包裝對(duì)象所替代。
參考資料
[1], Javascript權(quán)威指南第6版,189頁(yè)
[2], Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )
[3], Function.prototype.apply (thisArg, argArray)
- 詳解JavaScript函數(shù)callee、call、apply的區(qū)別
- JavaScript函數(shù)apply()和call()用法與異同分析
- JS中call和apply函數(shù)用法實(shí)例分析
- javascript中call,apply,bind函數(shù)用法示例
- javascript基于原型鏈的繼承及call和apply函數(shù)用法分析
- JavaScript中函數(shù)(Function)的apply與call理解
- 從JQuery源碼分析JavaScript函數(shù)的apply方法與call方法
- JavaScript中的apply和call函數(shù)詳解
- JavaScript函數(shù)Call、Apply原理實(shí)例解析
相關(guān)文章
重載toString實(shí)現(xiàn)JS HashMap分析
用過(guò)Java的都知道,里面有個(gè)功能強(qiáng)大的數(shù)據(jù)結(jié)構(gòu)——HashMap,它能提供鍵與值的對(duì)應(yīng)訪問(wèn)。不過(guò)熟悉JS的朋友也會(huì)說(shuō),JS里面到處都是hashmap,因?yàn)槊總€(gè)對(duì)象都提供了map[key]的訪問(wèn)形式。2011-03-03
JS實(shí)現(xiàn)可調(diào)整倒計(jì)時(shí)間代碼分享
這篇文章主要介紹了JS實(shí)現(xiàn)可調(diào)整倒計(jì)時(shí)間代碼,效果很酷炫,也很具有實(shí)用價(jià)值,感興趣的小伙伴們可以參考一下2015-08-08
微信小程序上傳圖片并等比列壓縮到指定大小的實(shí)例代碼
這篇文章主要介紹了微信小程序 上傳圖片并等比列壓縮到指定大小,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10
js實(shí)現(xiàn)上傳圖片及時(shí)預(yù)覽
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)上傳圖片及時(shí)預(yù)覽的相關(guān)資料,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2016-05-05
郁悶!ionic中獲取ng-model綁定的值為undefined如何解決
很是郁悶!ionic中獲取ng-model綁定的值為undefined,如何解決?2016-08-08

