你不知道的JavaScript基礎(chǔ):call And apply

寫在前面

在JavaScript中call和apply這兩個函數(shù)是比較基礎(chǔ)的東西害淤。因為一般的前端開發(fā)中用不到平窘,所以初入Web前端的程序員們并不是很清楚他們的用法炉旷、聯(lián)系及區(qū)別楷兽。愛鉆研探索的程序員地熄,或是已經(jīng)在前端開發(fā)中漸入佳境者多少會聽說或用到這兩個函數(shù),所以網(wǎng)上關(guān)于他們的介紹并不在少數(shù)芯杀。我在寫這篇之前也在網(wǎng)上搜索了一番端考,雖然大多數(shù)為復(fù)制粘貼相互轉(zhuǎn)載,但也有不少作者比較用心揭厚,寫的確有獨(dú)到之處却特。當(dāng)然我對于call和apply以及他們的出身用途也都有自己的理解。

從何而來

站在面向?qū)ο蟮慕嵌葋碚f筛圆,在JavaScript中所有使用function關(guān)鍵字定義的方法或函數(shù)裂明,都是Function對象(類)的一個實(shí)例對象。對象可以擁有自己的方法和屬性太援,而call和apply正是所有函數(shù)對象都具有的方法漾岳。請看下面的代碼段:

// 下面是使用兩種不同的方式定義函數(shù)了四個函數(shù)
> function fun1(str){console.log("fun1 say "+str)}
> fun2 = new Function("str","console.log('fun2 say '+str)");
> function fun3(a,b){console.log(a+b)}
> fun4 = new Function("a","b","console.log(a+b)");

//下面是對各個函數(shù)對象的call方法進(jìn)行測試,通過代碼大家不難發(fā)現(xiàn)粉寞,
//所有函數(shù)對象的call方法都是相等的
> fun1.call === Function.prototype.call
< true
> fun2.call === Function.prototype.call
< true
> fun3.call === Function.prototype.call
< true
> fun4.call === Function.prototype.call

//下面是對各個函數(shù)對象的apply方法進(jìn)行測試,通過代碼大家不難發(fā)現(xiàn)左腔,
//所有函數(shù)對象的apply方法都是相等的
> fun1.apply=== Function.prototype.apply
< true
> fun2.apply=== Function.prototype.apply
< true
> fun3.apply=== Function.apply
< true
> fun4.apply=== Function.apply

//下面是對Function類(其實(shí)也是一個函數(shù)對象)的一些測試唧垦,
//通過代碼我們發(fā)現(xiàn)Function原型prototype的call方法與Function的call方法相等,
//且Function原型prototype的apply方法與Function的apply方法相等

> Function.prototype.call === Function.call
< true
> Function.prototype.call === Function.call
< true

通過上面的代碼段我們可以了解到液样,F(xiàn)unction.prototype振亮,F(xiàn)unction巧还,以及所有函數(shù)對象的call和apply方法都相等的,也就是說這些對象中的這兩個方法其實(shí)本質(zhì)上是只兩個方法在被他們分別繼承反復(fù)重用了而已坊秸。

在JavaScript中麸祷,所有“函數(shù)對象”都是Function類的實(shí)例,無論這個函數(shù)對象是使用new Function()的方式定義褒搔,還是使用function關(guān)鍵字定義阶牍;包括Object類、甚至連Function類自身也都是Function類的對象星瘾,我們可以統(tǒng)稱他們?yōu)椤昂瘮?shù)對象”走孽。而call和apply這兩個方法就是在Function.prototype中定義的方法,所以會在所有的函數(shù)對象中通過原型鏈從Function.prototype中得到繼承琳状。這就是call和apply的由來磕瓷。

作用

call和apply的作用是相同的,都是為了改變函數(shù)運(yùn)行時的上下文念逞。說上下文可能不太好理解困食。下面通過一段代碼來解釋:
好長的一段代碼,如果你已經(jīng)理解了翎承,可以勇敢點(diǎn)跳過你認(rèn)為啰嗦的那部分代碼

//隨便定義兩個函數(shù)吧
function a(){
  console.log(this.val);
}

function b(){
  var str = "wfso";
  console.log(str);
}

//下面是對a和b兩個函數(shù)幾種不同的調(diào)用方式

// 通過下面的兩小段代碼硕盹,可以知道,函數(shù)的默認(rèn)上下文是window审洞,也可以說是global吧
> a();
< undefined

> var val = "val";
< a();
< val

// 對b的調(diào)用只是作為與a的對比
> b();
< wfso

// 創(chuàng)建一個對象w莱睁,然后把w當(dāng)作a函數(shù)對象的call和apply方法的參數(shù)
// 改變a函數(shù)的執(zhí)行上下文
> var w={val:"仵士杰"};
> a.call(w);
< 仵士杰
> a.apply(w);
< 仵士杰

// 為了有更清晰的結(jié)果,再創(chuàng)建一個對象v來做實(shí)驗吧
> var v={val:"www"};
> a.call(v);
< www
> a.apply(v);
< www

// 同樣作為對比芒澜,我們分別對b也做同樣的調(diào)用看看

> b.call(w);
< wfso
> b.apply(w);
< wfso

> b.call(v);
< wfso
> b.apply(v);
< wfso

如果我現(xiàn)在說仰剿,函數(shù)的執(zhí)行上下文其實(shí)就是在函數(shù)中this關(guān)鍵字引用的對象,你應(yīng)該不會有異議了吧痴晦。全局函數(shù)的默認(rèn)上下文是window南吮。而類中方法的默認(rèn)上下文是調(diào)用這個方法的對象。如果你要改變這種默認(rèn)的函數(shù)或方法執(zhí)行時的上下文件誊酌,就需要通過函數(shù)對象的call或apply方法來實(shí)現(xiàn)了部凑。

區(qū)別和用法 call OR apply

call 與 apply 在作用上是完全相同的,他們的區(qū)別體現(xiàn)調(diào)用時的參數(shù)傳遞上碧浊。

call 調(diào)用方法

調(diào)用call時如果需要參數(shù)傳遞涂邀,則需要把所有參數(shù)一一列出來。如下:

fun.call(ctx[,arg1[,arg2[,arg2[,……]]]]);

arg1,arg2,arg3是給fun函數(shù)傳的參數(shù)列表箱锐。

function a(str1,str2){console.log(this.val+"\n"+str1+"--"+str2)}
> v={val:"wfs"};
> a.call(v,"仵士杰","xt");
< wfs
< 仵士杰--xt

apply 調(diào)用方法

調(diào)用apply時如果需要參數(shù)傳遞比勉,則需要把所有參數(shù)放到一個數(shù)組里,然后把所有參數(shù)組成的數(shù)組作為一個參數(shù)傳遞給apply方法。如下:

fun.apply(ctx[,arguments]);

arguments是一個數(shù)組浩聋,里面存儲的是給fun函數(shù)傳的參數(shù)列表观蜗。

function a(str1,str2){console.log(this.val+"\n"+str1+"--"+str2)}
> v={val:"wfs"};
> a.apply(v,["仵士杰","xt"]);
< wfs
< 仵士杰--xt

扎然而止

好了,上面的介紹已經(jīng)是我能力的極限了衣洁,不想寫什么總結(jié)了墓捻。就這樣結(jié)束吧,打完收功坊夫!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砖第,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子践樱,更是在濱河造成了極大的恐慌厂画,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拷邢,死亡現(xiàn)場離奇詭異袱院,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瞭稼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門忽洛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人环肘,你說我怎么就攤上這事欲虚。” “怎么了悔雹?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵复哆,是天一觀的道長。 經(jīng)常有香客問我腌零,道長梯找,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任益涧,我火速辦了婚禮锈锤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闲询。我一直安慰自己久免,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布扭弧。 她就那樣靜靜地躺著阎姥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸽捻。 梳的紋絲不亂的頭發(fā)上丁寄,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天氨淌,我揣著相機(jī)與錄音,去河邊找鬼伊磺。 笑死,一個胖子當(dāng)著我的面吹牛删咱,可吹牛的內(nèi)容都是我干的屑埋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痰滋,長吁一口氣:“原來是場噩夢啊……” “哼摘能!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敲街,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤团搞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后多艇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逻恐,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年峻黍,在試婚紗的時候發(fā)現(xiàn)自己被綠了复隆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡姆涩,死狀恐怖挽拂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情骨饿,我是刑警寧澤亏栈,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站宏赘,受9級特大地震影響绒北,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜置鼻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一镇饮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧箕母,春花似錦储藐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至聂喇,卻和暖如春辖源,著一層夾襖步出監(jiān)牢的瞬間蔚携,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工克饶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酝蜒,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓矾湃,卻偏偏與公主長得像亡脑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邀跃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容