JS學習筆記 - 回調函數

本文章記錄本人在學習 JavaScript 中看書理解到的一些東西,加深記憶和而且整理記錄下來,方便以後的複習。node

什麼是回調函數

js裏函數都是對象,這表示它們能夠做爲參數傳遞給其餘的函數。舉例:當函數b()做爲參數傳遞給函數a(),那麼在某一時刻函數a()可能會執行或者調用函數b()。這種狀況下,函數b()就被稱爲回調函數,也能夠簡稱叫作回調(下面是栗子)。數組

JavaScript'use strict';

function a(callback) {
    callback();
}

function b() {
    console.log('hello callback');
}

a(b); // 注意 b() 做爲參數傳遞給 a() 的時候是不須要帶括號的

回調函數示例

假設有一個通用的函數執行一些複雜的處理工做,而且返回結果爲一個大塊數據(下面是栗子)。app

JavaScriptvar findeNodes = function () {
    var i = 10000,
        node = [],
        found;

    while (i) {
        i -= 1;
        node.push(found);
    }

    return nodes;
}

上面代碼定義函數findNodes(),它的任務是抓取頁面的dom tree,並返回一個你要的頁面元素數組。dom

在定義一個函數hide(),顧名思義它的做用是隱藏頁面中的節點(下面是栗子)。ide

JavaScriptvar hide = function (nodes) {
    for (var i = 0; i < nodes.length; i += 1) {
        nodes[i].style.display = 'block';
    }
}

// 執行函數
hide(findeNodes());

好了,要的效果都實現了,可是實現倒是低效的。由於hide()必須再次循環由findNodes()返回的數組節點。若是能避免這種循環,只須要在findNodes()中選擇即可隱藏節點,那麼這將是更高效的方式。可是若是在findNodes()中實現隱藏邏輯的話,因爲檢索和修改邏輯耦合,那麼他再也不是通用的函數。面對這種問題的解決方法是採用回調模式,能夠將所以節點邏輯以回調函數方式傳遞給findNodes()並委託執行(下面是栗子)。函數

JavaScript// 重構 findeNodes() 函數,並接受一個回調函數

var findeNodes = function (callback) {
    var i = 10000,
        nodes = [],
        found;

    while (i) {
        i -= 1;

        // 如今運行回調函數
        if (typof callback === 'function') {
            callback();
        }

        nodes.push(found);
    }
    return found;
}

上面的代碼只是作了對callback是否存在進行了判斷,若是存在的話嗎,那麼就執行該函數。其中,回調函數是可選的,所以後續的findeNodes()仍然能夠想之前同樣使用,而不會破壞以來舊API的原始代碼。學習

如今hide的實現就簡單多了,由於它不須要再去循環遍歷全部的節點了(下面是栗子)。this

JavaScript// 回調函數
var hide = function (nodes) {
    nodes.style.display = 'none';
}

// 找到指定的節點,並在後續執行中隱藏
findeNodes(hide);

回調函數與做用域

在上一個栗子中,回調函數執行的語句是這樣的:callback(parameters)code

雖然上面那句在大多數的場景上都是有效的,可是總會有一些場景,其回調函數並非一次性的匿名函數或者全局函數,而是對象的方法。若是該函數使用this來引用它所的屬性,這可能有是一個坑了(下面是栗子)。對象

JavaScript// 假設回調函數是 paint(),它是一個名爲 myapp 的對象的方法
var myapp = {};
myapp.color = 'green';
myapp.paint = function (nodes) {
    nodes.style.color = this.color;
}

// 而後用到上一個栗子的 findeNodes() 
findeNodes(myapp.paint); //

坑:this.color沒有被定義,由於findeNods()是一個全局函數,所以,對象的this是指向window的。

解決的方法有:

  • 另外傳遞該回調函數的所屬對象。這樣就須要修改一下findNodes()函數(下面是栗子)。
JavaScriptvar findNodes = function (callback, callback_obj) {
    // ...
    if (typof callback === 'function') {
            callback.call(callback_obj, found);
    }
    // ...
}

// 執行函數
findNodes(myapp.paint, myapp);

主要是經過call、apply來修改函數運行時的this指向。

  • 而後接着修改上面的方法,將方法做爲字符串傳遞,所以就不用兩次輸入該對象的名稱(下面是栗子)。
JavaScriptvar findNodes = function (callback, callback_obj) {
    // ...
    if (typof callback === 'string') {
        callback = callback_obj[callback];
    }
    // ...
    if (typof callback === 'function') {
            callback.call(callback_obj, found);
    }
    // ...
}

// 執行函數
findNodes('paint', myapp);

最後,若是文章有什麼錯誤和疑問的地方,請指出。與sf各位共勉!

相關文章
相關標籤/搜索