上一篇我們在討論 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
中加入了 setTimeout
,setTimeout
為非同步的處理方法,同步與非同步在前面文章有提到,它的第一個參數為時間到時要被執行的程式,第二個參數為延遲的時間 ( 豪秒 )。
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)?