iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Modern Web

我的JavaScript日常系列 第 28

JavaScript Day 28. Callback Function ( 回呼函式 )

上一篇我們在討論 AJAX 的時候,有另外提到 Callback Function,不知道怎麼的我突然想花更多的時間去研究這個 function,所以這一篇就用更多的 Callback Function 範例把它塞滿好了 (?)

Callback Function,也稱做「回呼函式」,在前面的例子中我們可以大概看到, Callback Function只會在滿足某項條件以後被動的去執行,簡單來說就是「在一個函式執行完後,會依照條件去執行傳遞進來的函式」。

直接進入範例:

var isFirst = function (callback) {
    console.log('is first!');
    callback(); // 執行傳入的 isSecond()
}

// callback function
var isSecond = function () {
    console.log('is second!')
}
isFirst(isSecond);

isFirst 函式執行完以後才會執行 isSecond 函式,並且 isSecond 會被代入到 callback,isSecond 即為一個 Callback Function。

結果:

is first!
is second!

但這樣其實看起來跟平常的函式沒有什麼太大的不同,平常的函式不也是長這個樣子嗎?

var isFirst = function (callback) {
    console.log('is first!');
}

var isSecond = function () {
    console.log('is second!')
}

isFirst();
isSecond();

結果:

is first!
is second!

我們可以來試試比較明顯的例子,以下面這個例子來說,isFirst 中加入了 setTimeoutsetTimeout 為非同步的處理方法,同步與非同步在前面文章有提到,它的第一個參數為時間到時要被執行的程式,第二個參數為延遲的時間 ( 豪秒 )。

var isFirst = function () {
		setTimeout(function() {
        console.log('is first!')
    }, 2000); // 非同步,2秒後才執行
}

var isSecond = function () {
    console.log('is second!')
}

isFirst();
isSecond();

結果:

is second!
// 2秒後
is first!

從結果來看 isFirst 函式被設定延遲,加上 setTimeout 是非同步方法,因此不會等到 isFirst 回傳結果,而是先繼續執行 isSecond 函式,那麼如果我們希望 isSecond 函式可以在印出 is first! 之後才執行呢?這時候就必須使用 Callback Function 來處理。

var isFirst = function (callback) {
		setTimeout(function() {
        console.log('is first!')
				callback();
    }, 2000); // 非同步,2秒後才執行
}

// callback function
var isSecond = function () {
    console.log('is second!')
}

isFirst(isSecond);

結果:

// 2秒後
is first!
is second!

可以看到,使用 Callback Function 之後,is second! 可以確保在 is first! 印出後才出現,符合 Callback Function 會在滿足一個條件以後才會再次執行另一個程式的原則。

另外再塞一個看起來比較複雜一點點的 Callback Function 範例:

//定義函式
function prepare(ingredients, callback) {
       console.log("Preparing" + ingredients);
       callback();
}

//調用函式
prepare("onions and garlic", function chop() {
       console.log("Chopping" );
});

prepare() 代入了兩個參數,第一個為 ingredients,然後使用 chop() 的 Callback Function 作為第二個參數,此時 chop() 會代入 callback(),力求簡潔的寫法把 chop() 直接代入到 prepare() 中,結果為:

Preparing onions and garlic
Chopping

呈上面的例子, Callback Function 也可以是匿名函式:

//定義函式
function prepare(ingredients, callback) {
       console.log("Preparing" + ingredients);
       callback();
}

//調用函式
prepare("onions and garlic", () => {
       console.log("Chopping" );
});

現在我們的 Callback Function 是匿名的,它不叫做「chop」了。

結果:

Preparing onions and garlic
Chopping

Callback Function 是作為另一個主函式傳遞參數的函式, Callback Function 在主函式內部執行,並且由主函式決定何時執行它。

現在已經知道執行 Callback Function 的主函式有權決定何時執行,而且不只這樣,主函式能替Callback Function 決定的東西很多,它也可以將參數傳遞給 Callback Function。底下為帶參數的Callback Function 例子:

//定義函式
function prepare(ingredients, callback) {
       console.log("Preparing " + ingredients);
			 // 這邊替 Callback Function 加上了參數
       callback(ingredients);
}

//調用函式
prepare("onions and garlic", function chop(arg) { 
			 // chop() 代入 arg 參數
       console.log("Chopping " + arg);
});

這邊我們不只是調用 chop() 這支 Callback Function,我們將它變成參數傳入,並且告訴它在執行的時候回傳 "Chopping " 以及參數。

結果:

Preparing onions and garlic
Chopping onions and garlic

雖然我覺得寫到這裡應該差不多了(X),但是 Callback Function 的好處比我原本想像的還更多,因此我只好繼續寫下去。不過好加在這是最後一個例子了,腦袋得以回氧再做衝刺,哈哈。

Callback Function 也是函式,這意思是說它也可以做任何函式能做的事情,這邊有一個例子,假設我們希望回傳底下這個結果:

Preparing onions and garlic
Chopping onions

為了呈現這樣的結果,表示 Callback Function 必須過濾掉不要用的詞。

function chop(ingredients){
     var value = ingredients.match(/\bonions\b/g);
     if (value){
				console.log("Chopping " + value);
		 } else {
				console.log("Not chopping");
		 }
}

在這個範例中,它必須確認 “ onions ” 這個詞有沒有在參數中,如果有就回傳 “ Chopping onions ”,如果沒有則回傳 " Not chopping "。

function prepare(ingredients, callback) {
       console.log("Preparing " + ingredients);
       callback(ingredients); 
}

function chop(ingredients){
     var value = ingredients.match(/\bonions\b/g);
     if (value){
				console.log("Chopping " + value);
		 } else {
				console.log("Not chopping");
		 }
}

prepare("onions and garlic", chop);

最後這個例子可能複雜了一點,主要是它除了調用 Callback Function 之外,還另外使用了 match() 方法來查找字串是否有匹配,不過如果對 match() 方法是有理解的,這最後一個範例應該也還是不難懂,不妨在看這一範例的時候,先去了解一下 match() 方法,比較不會覺得恐慌 (?)

參考資料:

JavaScript 什麼是Callback函式 (Callback Function)?


上一篇
JavaScript Day 27. AJAX、Request、Response
下一篇
JavaScript Day 29. 立即函式 IIFE
系列文
我的JavaScript日常31

尚未有邦友留言

立即登入留言