JavaScript - 回調(diào)函數(shù)

這里我想跟你聊聊我理解的回調(diào)函數(shù)(callback)煮仇。

回調(diào)函數(shù),我覺得可以理解成作為參數(shù)傳遞的函數(shù)對(duì)象舔示。因?yàn)樵?JavaScript 中函數(shù)有比較高的等級(jí)(是一種基本類型尊浓,嗯粪狼,應(yīng)該可以這樣講吧)退腥,可以獨(dú)立地進(jìn)行使用。

而在 Java 中再榄,可能只有作為類的方法的“函數(shù)”存在吧狡刘,不存在可以單獨(dú)使用的函數(shù)。當(dāng)然在 Java 中困鸥,我“揣測(cè)”函數(shù)嗅蔬,或者叫方法(method)更合適,可能只有被調(diào)用的使用方式疾就,例如: foo.method() 澜术。

在 JavaScript 中,函數(shù)還是挺獨(dú)立的猬腰。例如鸟废,盡管有的時(shí)候一個(gè)函數(shù)在聲明的時(shí)候就是作為某個(gè)對(duì)象的方法的形式,但仍然可以撇開這個(gè)對(duì)象來使用姑荷。這里用到了函數(shù)的 .call().apply() 方法(這里就叫方法吧盒延,不再繞來繞去了)。例如:

var Person = function (name) {
    this.name = name;
    this.getName = function () {
        return this.name;
    };
};

我先用自己的話跟你大致說下上面的代碼里面做了什么事情鼠冕,有些東西是我之前的文章還沒有講到的添寺,不過相信你可能也都懂的:

  1. 首先,我聲明了一個(gè)變量和一個(gè)函數(shù)懈费,函數(shù)本身沒有名稱计露,將其作為值賦給了變量 Person,這是最主要的結(jié)構(gòu);

  2. 然后票罐,再來看這個(gè)匿名函數(shù)的內(nèi)部叉趣,我給 this 對(duì)象(且這么叫吧)設(shè)置了兩個(gè)屬性,屬性 name 的值為匿名函數(shù)的參數(shù) name胶坠,屬性 getName 的值為一個(gè)匿名函數(shù);

  3. 最后繁堡,我們看下 getName 對(duì)應(yīng)的匿名函數(shù)干了什么:它返回了 this 的屬性 name 的值沈善。

對(duì)于 Person 的使用方式,之前提到過(不過定義的形式可能稍有不同椭蹄,這不是重點(diǎn))闻牡,可以這樣用:

var me = new Person("luobo");
me.getName(); // "luobo"

這里說了挺多題外的東西,現(xiàn)在我們來看上面 me 這個(gè)對(duì)象的方法 getName()绳矩。盡管形式上是對(duì)象的方法罩润,而且在一開始定義的時(shí)候就確定了其方法的目的(這種 this.foo = ... 的方式我會(huì)在講繼承的時(shí)候再跟你多聊一些),但是由于其函數(shù)的本質(zhì)翼馆,仍然可以單獨(dú)來使用:

me.getName.call({ name: "Mickey" }); // "Mickey"

注意割以,這里 me.getName 只是為了引用到實(shí)際的函數(shù)(對(duì)象),以 .call() 來調(diào)用時(shí)傳入了新的“上下文對(duì)象” { name: "Mickey" }应媚,而這個(gè)上下文對(duì)象在函數(shù)執(zhí)行時(shí)會(huì)替換函數(shù)內(nèi)部使用的 this严沥,有點(diǎn)了解了嗎?

所以中姜,實(shí)際上對(duì)于上文中聲明的 Person 所對(duì)應(yīng)的匿名函數(shù)消玄,也可以這樣來使用:

var me = {};
Person.call(me, "luobo");
me.getName(); // "luobo"

再引申一點(diǎn)來講,使用 new Person() 這樣的形式來獲得一個(gè)對(duì)象丢胚,那么在 Person 內(nèi)部的 this 就是對(duì)應(yīng)這個(gè)即將返回的對(duì)象 翩瓜。(嚴(yán)格來說不完全是,在 Person 對(duì)應(yīng)的匿名函數(shù)有明確定義的其他返回值時(shí)就不再返回這個(gè) this 對(duì)象啦)

雖然是要講回調(diào)函數(shù)携龟,可是我花了好多時(shí)間來講每個(gè)函數(shù)都可以被獨(dú)立調(diào)用這件事兔跌,還說到函數(shù)中的 this 在函數(shù)執(zhí)行時(shí)可以明確指定(通過 .call() 傳入的第一個(gè)參數(shù)即作為函數(shù)內(nèi)部 this 所指向的對(duì)象),這些都是會(huì)用到的峡蟋。

下面我舉個(gè)使用回調(diào)函數(shù)的栗子:

$("#myDiv").on("click", function () {
    this.innerHTML = "you clicked me!";
});

這個(gè)栗子中浮定,我們使用 jQuery 給一個(gè) id 為 myDiv 的元素綁定了 click 事件的處理程序,這里的事件處理程序就是一個(gè)回調(diào)函數(shù)层亿。當(dāng)然回調(diào)函數(shù)并非是一種特殊類型的對(duì)象桦卒,其實(shí)就是普通的函數(shù),但是被作為其他函數(shù)的參數(shù)傳遞匿又,在某個(gè)時(shí)刻才會(huì)被選擇性地使用方灾。

單純看回調(diào)函數(shù)不是特別有趣,不過你應(yīng)該注意到上面這個(gè)回調(diào)函數(shù)的定義中使用 this,那么這個(gè) this 又是指向什么對(duì)象呢裕偿?

實(shí)際上洞慎,這是由 jQuery 提供的機(jī)制,在事件處理程序被調(diào)用時(shí)嘿棘,this 會(huì)指向事件的目標(biāo)對(duì)象劲腿,這里也就是被點(diǎn)擊的 myDiv 元素,而 HTML 元素有 innerHTML 屬性鸟妙,就是上面的使用方式了焦人。這是怎么實(shí)現(xiàn)的呢,合理揣測(cè)下的話重父,肯定是這個(gè)回調(diào)函數(shù)在調(diào)用是被顯式指定了“上下文對(duì)象” this花椭,有可能就是通過 .call().apply() 的方式。

另外房午,由于回調(diào)函數(shù)會(huì)在什么時(shí)候被執(zhí)行矿辽,可能是不確定,甚至也可能永遠(yuǎn)不會(huì)被執(zhí)行郭厌。而且在上面的這種情況下袋倔,這個(gè)回調(diào)函數(shù)甚至要在未來的某個(gè)時(shí)候才會(huì)執(zhí)行,這就有了一個(gè)“異步”的感覺折柠,也就是說代碼不是從上到下依次執(zhí)行奕污,前面的代碼執(zhí)行完畢后面的才會(huì)執(zhí)行(這個(gè)可以叫做“同步”啦)。

在使用 Ajax 時(shí)液走,我們可以指定請(qǐng)求是同步還是異步的方式碳默,同步的方式下比較好理解,一定是這個(gè)請(qǐng)求接收到服務(wù)器響應(yīng)或者超時(shí)失敗后缘眶,后面的代碼才會(huì)執(zhí)行嘱根。這種情況下我們編寫需要在一個(gè) Ajax 請(qǐng)求后才能做的時(shí)候,例如 alert("Ajax 請(qǐng)求已完成巷懈!")该抒,是比較容易的。不過壞處是代碼在執(zhí)行到這里的時(shí)候會(huì)等待 Ajax 請(qǐng)求被響應(yīng)顶燕,一切都停了下來凑保。如果不想讓世界暫停下來,就可以使用 Ajax 異步的模式(這也是通常的使用方式)涌攻,然后把想要做的事情以回調(diào)函數(shù)的形式包裝一下欧引,等待請(qǐng)求在未來有個(gè)結(jié)果(響應(yīng)、超時(shí)恳谎、意外終止等)后執(zhí)行芝此。舉個(gè)栗子:

$.ajax("/foo.jsp").done(function () {
    alert("成功憋肖!");
}).fail(function () {
    alert("失敗婚苹!");
});

這里分別為請(qǐng)求成功和失敗兩種情況指定了回調(diào)函數(shù)岸更。

關(guān)于回調(diào)函數(shù),咱們就聊這么多吧膊升。

擴(kuò)展:

  • 關(guān)于“異步”執(zhí)行怎炊,有沒有考慮過專門去使用它的情況?
    例如廓译,代碼執(zhí)行時(shí)間預(yù)期會(huì)很長(zhǎng)评肆,為避免瀏覽器不響應(yīng)用戶交互,人為地將代碼分為多個(gè)部分分別執(zhí)行责循,從而使得每個(gè)部分執(zhí)行時(shí)間不會(huì)很長(zhǎng)糟港。
  • 主動(dòng)地讓代碼“異步”執(zhí)行的方法攀操?
    常見的有 setTimeout院仿,另外還有借助瀏覽器的事件機(jī)制實(shí)現(xiàn)的,如為新創(chuàng)建的 img 元素指定 onload 事件的方式等等速和。
  • 異步執(zhí)行的代碼多層嵌套的處理
    因?yàn)橐曰卣{(diào)函數(shù)的方式來編寫異步執(zhí)行代碼歹垫,可能會(huì)很多級(jí)匿名函數(shù)互相嵌套的情況,代碼可讀性會(huì)比較差颠放。這種情況下一個(gè)選擇是可以使用一些第三方的庫排惨,如 when.js。其實(shí) jQuery 也提供了異步機(jī)制碰凶,可以看下 deffered暮芭,我們常用的 jQuery 的 ajax 函數(shù)也基于這個(gè)東東改造過。

接下來還想跟你聊聊:

  • JavaScript - 作用域和“閉包”
  • JavaScript - 繼承和“類”
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末欲低,一起剝皮案震驚了整個(gè)濱河市辕宏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌砾莱,老刑警劉巖瑞筐,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異腊瑟,居然都是意外死亡聚假,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門闰非,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膘格,“玉大人,你說我怎么就攤上這事财松〈程唬” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)政敢。 經(jīng)常有香客問我其徙,道長(zhǎng),這世上最難降的妖魔是什么喷户? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任唾那,我火速辦了婚禮,結(jié)果婚禮上褪尝,老公的妹妹穿的比我還像新娘闹获。我一直安慰自己,他們只是感情好河哑,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布避诽。 她就那樣靜靜地躺著,像睡著了一般璃谨。 火紅的嫁衣襯著肌膚如雪沙庐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天佳吞,我揣著相機(jī)與錄音拱雏,去河邊找鬼。 笑死底扳,一個(gè)胖子當(dāng)著我的面吹牛铸抑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衷模,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼鹊汛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了阱冶?” 一聲冷哼從身側(cè)響起刁憋,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熙揍,沒想到半個(gè)月后职祷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡届囚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年有梆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片意系。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泥耀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛔添,到底是詐尸還是另有隱情痰催,我是刑警寧澤兜辞,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站夸溶,受9級(jí)特大地震影響逸吵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缝裁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一扫皱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捷绑,春花似錦韩脑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壮吩,卻和暖如春进苍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粥航。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工琅捏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留生百,地道東北人递雀。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蚀浆,于是被迫代替她去往敵國(guó)和親缀程。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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

  • 回調(diào)函數(shù)就是一個(gè)通過函數(shù)指針調(diào)用的函數(shù)市俊。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù)杨凑,當(dāng)這個(gè)指針被用為調(diào)用...
    小沙鷹168閱讀 508評(píng)論 0 1
  • 什么是回調(diào)或高級(jí)函數(shù) 在JavaScrip中,function是內(nèi)置對(duì)象摆昧,它可以存儲(chǔ)在變量中撩满,通過參數(shù)傳遞給另一個(gè)...
    另一只小白閱讀 735評(píng)論 0 4
  • 五十三:請(qǐng)解釋 JavaScript 中 this 是如何工作的。1.方法調(diào)用模式當(dāng)一個(gè)函數(shù)被保存為一個(gè)對(duì)象的屬性...
    Arno_z閱讀 581評(píng)論 0 2
  • 我們先來看看回調(diào)的英文定義:A callback is a function that is passed as ...
    邁克高閱讀 1,592評(píng)論 0 3
  • 磚家與雜家的區(qū)別 ①磚家專注于一件事绅你,被人稱為工匠 ②雜家來回于N件事伺帘,被人稱為投機(jī)取巧 天下之大,唯有專注 ①陽...
    陽光創(chuàng)客敖偉偉閱讀 158評(píng)論 0 0