成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript高階函數(shù)的應(yīng)用

shusen / 3414人閱讀

摘要:定義高階函數(shù)是指至少滿足下列條件之一的函數(shù)函數(shù)可以作為參數(shù)被傳遞函數(shù)可以作為返回值輸出。參考資料設(shè)計(jì)模式與開發(fā)實(shí)踐第章高階函數(shù)

定義

高階函數(shù)是指至少滿足下列條件之一的函數(shù):

函數(shù)可以作為參數(shù)被傳遞;

函數(shù)可以作為返回值輸出。

JavaScript語言中的函數(shù)顯然滿足高階函數(shù)的條件,在實(shí)際開發(fā)中,無論是將函數(shù)當(dāng)作參數(shù)傳遞,還是讓函數(shù)的執(zhí)行結(jié)果返回另外一個函數(shù),這兩種情形都有很多應(yīng)用場景,以下就是一些高階函數(shù)的應(yīng)用。

應(yīng)用 作為參數(shù)傳遞 ajax異步請求
// callback為待傳入的回調(diào)函數(shù)
var getUserInfo = function(userId, callback) {
     $.ajax("http://xxx.com/getUserInfo?" + userId, function(data) {
        if (typeof callback === "function") {
            callback(data);
        }
    });
}

getUserInfo(13157, function(data) {
    alert (data.userName);
});
Array.prototype.sort

Array.prototype.sort接受一個函數(shù)當(dāng)作參數(shù),這個函數(shù)里面封裝了數(shù)組元素的排序規(guī)則。從Array.prototype.sort的使用可以看到,我們的目的是對數(shù)組進(jìn)行排序,這是不變的部分;而使用什么規(guī)則去排序,則是可變的部分。把可變的部分封裝在函數(shù)參數(shù)里,動態(tài)傳入Array.prototype.sort,使Array.prototype.sort方法成為了一個非常靈活的方法。

//從小到大排列
[1, 4, 3].sort(function(a, b) {
    return a - b;
});
// 輸出: [1, 3, 4]

//從大到小排列
[1, 4, 3].sort(function(a, b) {
    return b - a;
});
// 輸出: [4, 3, 1]
作為返回值 判斷數(shù)據(jù)的類型
var Type = {};

for (var i = 0, type; type = ["String", "Array", "Number"][i++];) {
    (function(type) {
        Type["is" + type] = function(obj) {
            return Object.prototype.toString.call(obj) === "[object "+ type +"]";
           }
       })(type)
};

Type.isArray([]);     // 輸出:true
Type.isString("str");     // 輸出:true
單例模式
var getSingle = function(fn) {
    var ret;
    return function() {
        return ret || (ret = fn.apply(this, arguments));
    };
};
實(shí)現(xiàn)AOP

AOP(面向切面編程)的主要作用是把一些跟核心業(yè)務(wù)邏輯模塊無關(guān)的功能抽離出來,這些跟業(yè)務(wù)邏輯無關(guān)的功能通常包括日志統(tǒng)計(jì)、安全控制、異常處理等。把這些功能抽離出來之后,再通過“動態(tài)織入”的方式摻入業(yè)務(wù)邏輯模塊中。這樣做的好處首先是可以保持業(yè)務(wù)邏輯模塊的純凈和高內(nèi)聚性,其次是可以很方便地復(fù)用日志統(tǒng)計(jì)等功能模塊。

通常,在JavaScript中實(shí)現(xiàn)AOP,都是指把一個函數(shù)“動態(tài)織入”到另外一個函數(shù)之中,具體的實(shí)現(xiàn)技術(shù)有很多,下面的例子通過擴(kuò)展Function.prototype來做到這一點(diǎn)。

Function.prototype.before = function(beforefn) {
    var __self = this;    // 保存原函數(shù)的引用
    return function() {    // 返回包含了原函數(shù)和新函數(shù)的"代理"函數(shù)
        beforefn.apply(this, arguments);     // 執(zhí)行新函數(shù),修正this
        return __self.apply(this, arguments);    // 執(zhí)行原函數(shù)
    }
};

Function.prototype.after = function(afterfn) {
    var __self = this;
    return function() {
        var ret = __self.apply(this, arguments);
        afterfn.apply(this, arguments);
        return ret;
    }
};

var func = function() {
    console.log(2);
};

func = func.before(function() {
    console.log(1);
}).after(function() {
    console.log(3);
});

func();

// 按順序打印出1,2,3
currying

currying(函數(shù)柯里化),又稱部分求值。一個currying的函數(shù)首先會接受一些參數(shù),接受了這些參數(shù)之后,該函數(shù)并不會立即求值,而是繼續(xù)返回另外一個函數(shù),剛才傳入的參數(shù)在函數(shù)形成的閉包中被保存起來。待到函數(shù)被真正需要求值的時候,之前傳入的所有參數(shù)都會被一次性用于求值。

// 通用currying函數(shù),接受一個參數(shù),即將要被currying的函數(shù)
var currying = function(fn) {
    var args = [];
    return function() {
        if (arguments.length === 0) {
            return fn.apply(this, args);
        } else {
            [].push.apply(args, arguments);
            return arguments.callee;
        }
    }
};

// 將被currying的函數(shù)
var cost = (function() {
    var money = 0;
    return function() {
        for (var i = 0, l = arguments.length; i < l; i++) {
            money += arguments[i];
        }
        return money;
    }
})();

var cost = currying( cost );    // 轉(zhuǎn)化成currying函數(shù)

cost( 100 );    // 未真正求值
cost( 200 );    // 未真正求值
cost( 300 );    // 未真正求值

console.log (cost());     // 求值并輸出:600
uncurrying

在JavaScript中,當(dāng)我們調(diào)用對象的某個方法時,其實(shí)不用去關(guān)心該對象原本是否被設(shè)計(jì)為擁有這個方法,這是動態(tài)類型語言的特點(diǎn),也是常說的鴨子類型思想。

同理,一個對象也未必只能使用它自身的方法,那么有什么辦法可以讓對象去借用一個原本不屬于它的方法呢?答案對于我們來說很簡單,call和apply都可以完成這個需求,因?yàn)橛胏all和apply可以把任意對象當(dāng)作this傳入某個方法,這樣一來,方法中用到this的地方就不再局限于原來規(guī)定的對象,而是加以泛化并得到更廣的適用性。

而uncurrying的目的是將泛化this的過程提取出來,將fn.call或者fn.apply抽象成通用的函數(shù)。

// uncurrying實(shí)現(xiàn)
Function.prototype.uncurrying = function() {
    var self = this;
    return function() {
        return Function.prototype.call.apply(self, arguments);
    }
};

// 將Array.prototype.push進(jìn)行uncurrying,此時push函數(shù)的作用就跟Array.prototype.push一樣了,且不僅僅局限于只能操作array對象。
var push = Array.prototype.push.uncurrying();

var obj = {
    "length": 1,
    "0": 1
};

push(obj, 2);
console.log(obj);   // 輸出:{0: 1, 1: 2, length: 2}
函數(shù)節(jié)流

當(dāng)一個函數(shù)被頻繁調(diào)用時,如果會造成很大的性能問題的時候,這個時候可以考慮函數(shù)節(jié)流,降低函數(shù)被調(diào)用的頻率。

throttle函數(shù)的原理是,將即將被執(zhí)行的函數(shù)用setTimeout延遲一段時間執(zhí)行。如果該次延遲執(zhí)行還沒有完成,則忽略接下來調(diào)用該函數(shù)的請求。throttle函數(shù)接受2個參數(shù),第一個參數(shù)為需要被延遲執(zhí)行的函數(shù),第二個參數(shù)為延遲執(zhí)行的時間。

var throttle = function(fn, interval) {
    var __self = fn,    // 保存需要被延遲執(zhí)行的函數(shù)引用
        timer,      // 定時器
        firstTime = true;    // 是否是第一次調(diào)用

    return function() {
        var args = arguments,
            __me = this;

        if (firstTime) {    // 如果是第一次調(diào)用,不需延遲執(zhí)行
            __self.apply(__me, args);
            return firstTime = false;
        }

        if (timer) {    // 如果定時器還在,說明前一次延遲執(zhí)行還沒有完成
            return false;
        }

        timer = setTimeout(function() {  // 延遲一段時間執(zhí)行
            clearTimeout(timer);
            timer = null;
            __self.apply(__me, args);
        }, interval || 500 );
    };
};

window.onresize = throttle(function() {
    console.log(1);
}, 500 );
分時函數(shù)

當(dāng)一次的用戶操作會嚴(yán)重地影響頁面性能,如在短時間內(nèi)往頁面中大量添加DOM節(jié)點(diǎn)顯然也會讓瀏覽器吃不消,我們看到的結(jié)果往往就是瀏覽器的卡頓甚至假死。

這個問題的解決方案之一是下面的timeChunk函數(shù),timeChunk函數(shù)讓創(chuàng)建節(jié)點(diǎn)的工作分批進(jìn)行,比如把1秒鐘創(chuàng)建1000個節(jié)點(diǎn),改為每隔200毫秒創(chuàng)建8個節(jié)點(diǎn)。

timeChunk函數(shù)接受3個參數(shù),第1個參數(shù)是創(chuàng)建節(jié)點(diǎn)時需要用到的數(shù)據(jù),第2個參數(shù)是封裝了創(chuàng)建節(jié)點(diǎn)邏輯的函數(shù),第3個參數(shù)表示每一批創(chuàng)建的節(jié)點(diǎn)數(shù)量。

var timeChunk = function(ary, fn, count) {
    var t;

    var start = function() {
        for ( var i = 0; i < Math.min( count || 1, ary.length ); i++ ){
            var obj = ary.shift();
            fn( obj );
        }
     };

     return function() {
        t = setInterval(function() {
          if (ary.length === 0) {  // 如果全部節(jié)點(diǎn)都已經(jīng)被創(chuàng)建好
              return clearInterval(t);
          }
          start();
        }, 200);    // 分批執(zhí)行的時間間隔,也可以用參數(shù)的形式傳入
    };
};
惰性加載函數(shù)

在Web開發(fā)中,因?yàn)闉g覽器之間的實(shí)現(xiàn)差異,一些嗅探工作總是不可避免。比如我們需要一個在各個瀏覽器中能夠通用的事件綁定函數(shù)addEvent,常見的寫法如下:

方案一:

var addEvent = function(elem, type, handler) {
    if (window.addEventListener) {
       return elem.addEventListener(type, handler, false);
    }
    
    if (window.attachEvent) {
          return elem.attachEvent("on" + type, handler);
    }
};

缺點(diǎn):當(dāng)它每次被調(diào)用的時候都會執(zhí)行里面的if條件分支,雖然執(zhí)行這些if分支的開銷不算大,但也許有一些方法可以讓程序避免這些重復(fù)的執(zhí)行過程。

方案二:

var addEvent = (function() {
    if (window.addEventListener) {
        return function(elem, type, handler) {
            elem.addEventListener(type, handler, false);
        }
    }
    if (window.attachEvent) {
        return function(elem, type, handler) {
            elem.attachEvent("on" + type, handler);
        }
    }
})();

缺點(diǎn):也許我們從頭到尾都沒有使用過addEvent函數(shù),這樣看來,一開始的瀏覽器嗅探就是完全多余的操作,而且這也會稍稍延長頁面ready的時間。

方案三:

var addEvent = function(elem, type, handler) {
        if (window.addEventListener) {
           addEvent = function(elem, type, handler) {
               elem.addEventListener(type, handler, false);
           }
        } else if (window.attachEvent) {
            addEvent = function(elem, type, handler) {
                elem.attachEvent("on" + type, handler);
            }
        }
        addEvent(elem, type, handler);
    };

此時addEvent依然被聲明為一個普通函數(shù),在函數(shù)里依然有一些分支判斷。但是在第一次進(jìn)入條件分支之后,在函數(shù)內(nèi)部會重寫這個函數(shù),重寫之后的函數(shù)就是我們期望的addEvent函數(shù),在下一次進(jìn)入addEvent函數(shù)的時候,addEvent函數(shù)里不再存在條件分支語句。

參考資料:

《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 第 3 章 高階函數(shù)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89806.html

相關(guān)文章

  • 學(xué)習(xí)React之前你需要知道JavaScript基礎(chǔ)知識

    摘要:和類在開始時遇到類組件,只是需要有關(guān)類的基礎(chǔ)。畢竟,中的條件呈現(xiàn)僅再次顯示大多數(shù)是而不是特定的任何內(nèi)容。 在我的研討會期間,更多的材料是關(guān)于JavaScript而不是React。其中大部分歸結(jié)為JavaScript ES6以及功能和語法,但也包括三元運(yùn)算符,語言中的簡寫版本,此對象,JavaScript內(nèi)置函數(shù)(map,reduce,filter)或更常識性的概念,如:可組合性,可重用...

    bitkylin 評論0 收藏0
  • 一文帶你了解什么是JavaScript 函數(shù)式編程?

    摘要:前言函數(shù)式編程在前端已經(jīng)成為了一個非常熱門的話題。整個過程就是體現(xiàn)了函數(shù)式編程的核心思想通過函數(shù)對數(shù)據(jù)進(jìn)行轉(zhuǎn)換。高階函數(shù)函數(shù)式編程傾向于復(fù)用一組通用的函數(shù)功能來處理數(shù)據(jù),它通過使用高階函數(shù)來實(shí)現(xiàn)。 前言 函數(shù)式編程在前端已經(jīng)成為了一個非常熱門的話題。在最近幾年里,我們看到非常多的應(yīng)用程序代碼庫里大量使用著函數(shù)式編程思想。 本文將略去那些晦澀難懂的概念介紹,重點(diǎn)展示在 JavaScrip...

    acrazing 評論0 收藏0
  • 【進(jìn)階 6-1 期】JavaScript 高階函數(shù)淺析

    摘要:引言本期開始介紹中的高階函數(shù),在中,函數(shù)是一種特殊類型的對象,它們是。簡單來說,高階函數(shù)是一個接收函數(shù)作為參數(shù)傳遞或者將函數(shù)作為返回值輸出的函數(shù)。我們來看看使用它們與不使用高階函數(shù)的方案對比。引言 本期開始介紹 JavaScript 中的高階函數(shù),在 JavaScript 中,函數(shù)是一種特殊類型的對象,它們是 Function objects。那什么是高階函數(shù)呢?本節(jié)將通過高階函數(shù)的定義來展...

    yiliang 評論0 收藏0
  • 高階函數(shù)應(yīng)用 —— 柯里化與反柯里化

    摘要:柯里化通用式上面的柯里化函數(shù)沒涉及到高階函數(shù),也不具備通用性,無法轉(zhuǎn)換形參個數(shù)任意或未知的函數(shù),我們接下來封裝一個通用的柯里化轉(zhuǎn)換函數(shù),可以將任意函數(shù)轉(zhuǎn)換成柯里化。 showImg(https://segmentfault.com/img/remote/1460000018998373); 閱讀原文 前言 在 JavaScript 中,柯里化和反柯里化是高階函數(shù)的一種應(yīng)用,在這之前...

    wyk1184 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<