Javascript 是你的高階函數(shù)(高級(jí)應(yīng)用)
在通常的編程語言中,函數(shù)的參數(shù)只能是基本類型或者對(duì)象引用,返回值也只是基本數(shù)據(jù)類型或?qū)ο笠谩5贘avascript中函數(shù)作為一等公民,既可以當(dāng)做參數(shù)傳遞,也可以被當(dāng)做返回值返回。所謂高階函數(shù)就是可以把函數(shù)作為參數(shù),或者是將函數(shù)作為返回值的函數(shù)。這兩種情形在實(shí)際開發(fā)中有很多應(yīng)用場(chǎng)景,本文是我在工作學(xué)習(xí)中遇到的幾種應(yīng)用場(chǎng)景的總結(jié)。
回調(diào)函數(shù)
代碼復(fù)用是衡量一個(gè)應(yīng)用程序的重要標(biāo)準(zhǔn)之一。通過將變化的業(yè)務(wù)邏輯抽離封裝在回調(diào)函數(shù)中能夠有效的提高代碼復(fù)用率。比如ES5中為數(shù)組增加的forEach方法,遍歷數(shù)組,對(duì)每個(gè)元素調(diào)用同一個(gè)函數(shù)。
array = {}; array.forEach = function(arr, fn){ for (var i = 0, len = arr.length; i < len; i++) { fn(arr[i], i, arr); } }
通過回調(diào)函數(shù)將業(yè)務(wù)的重點(diǎn)聚焦在回調(diào)函數(shù)中,而不必每次都要重復(fù)編寫遍歷代碼。
偏函數(shù)
作為將函數(shù)當(dāng)做返回值輸出的典型應(yīng)用就是偏函數(shù)。所謂偏函數(shù)是指創(chuàng)建一個(gè)調(diào)用另外一個(gè)部分——參數(shù)或變量已經(jīng)預(yù)置的函數(shù)——的函數(shù)的用法。反正看著定義我是沒理解這東東干嘛的。咱們還是先看例子吧,偏函數(shù)最典型的例子就是類型判斷。
Javascript對(duì)象都擁有三個(gè)屬性:原型屬性、類屬性、可擴(kuò)展性。(不知道的同學(xué)要回去翻犀牛書哦,page:138)類屬性是一個(gè)字符串,Javascript中并未直接提供,但我們可以利用Object.prototype.toString來間接得到。該函數(shù)總是返回如下形式:
[object Class]
因此我們可以編寫一系列isType函數(shù)。
代碼如下:
isString = function(obj){ return Object.prototype.toString.call(obj) === "[object String]"; } isNumber = function(obj){ return Object.prototype.toString.call(obj) === "[object Number]"; } isArray = function(obj){ return Object.prototype.toString.call(obj) === "[object Array]"; }
這幾個(gè)函數(shù)中大部分代碼是重復(fù)的,這時(shí)高階函數(shù)便華麗麗的登場(chǎng)了:
isType = function(type) { return function(obj) { return Object.prototype.toString.call(obj) === "[object " + type + "]"; } } isString = isType('String'); isNumber = isType('Number'); isArray = isType('Array');
所以通過指定部分參數(shù)來返回一個(gè)新的定制函數(shù)的形式就是偏函數(shù)。
currying(柯里化)
currying又稱部分求值。一個(gè)currying的函數(shù)首先會(huì)接受一些參數(shù),接受這些參數(shù)之后,函數(shù)并不會(huì)立即求值,而是繼續(xù)返回另一個(gè)函數(shù),剛才傳入的參數(shù)在函數(shù)形成的閉包中被保存起來。待到函數(shù)被真正需要求值的時(shí)候,之前傳入的所有參數(shù)都會(huì)被一次性用于求值。
var currying = function(fn) { var args = []; return function() { if (arguments.length === 0) { return fn.applay(this, args); } else { args = args.concat(arguments); return arguments.callee; } } }
假設(shè)我們以計(jì)算一個(gè)月每天花銷為例:
var currying = function(fn) { debugger; var args = []; return function() { if (arguments.length === 0) { return fn.apply(this, args); } else { Array.prototype.push.apply(args, arguments); return arguments.callee; } } } cost = function(){ var sum = 0; for (var i = 0, len = arguments.length; i < len; i++) { sum += arguments[i]; } return sum; } var cost = currying(cost); cost(100); cost(200); alert(cost())
事件節(jié)流
在某些場(chǎng)景下,某些事件可能會(huì)被重復(fù)的觸發(fā),但事件處理函數(shù)并不需要每次都執(zhí)行。比如在window.resize事件中進(jìn)行復(fù)雜的邏輯計(jì)算,如果用戶頻繁的改變?yōu)g覽器大小,復(fù)雜計(jì)算會(huì)對(duì)性能造成嚴(yán)重影響;有時(shí)這些邏輯計(jì)算并不需要每次rezise時(shí)都觸發(fā),只需要計(jì)算有限的幾次便可以。這時(shí)我們需要根據(jù)時(shí)間段來忽略一些事件請(qǐng)求。請(qǐng)看以下節(jié)流函數(shù):
function throttle(fn, interval) { var doing = false; return function() { if (doing) { return; } doing = true; fn.apply(this, arguments); setTimeout(function() { doing = false; }, interval); } } window.onresize = throttle(function(){ console.log('execute'); }, 500);
通過控制函數(shù)執(zhí)行時(shí)間,可以在函數(shù)執(zhí)行次數(shù)與功能需求之間達(dá)到完美平衡。另一個(gè)事件是mousemove。如果我們給一個(gè)dom元素綁定該事件,鼠標(biāo)在改元素上移動(dòng)時(shí),該事件便會(huì)重復(fù)觸發(fā)。
事件結(jié)束
對(duì)于某些可以頻繁觸發(fā)的事件,有時(shí)候我們希望在事件結(jié)束后進(jìn)行一系列操作。這時(shí)我們可以利用高階函數(shù)做如下處理:
function debounce(fn, interval) { var timer = null; function delay() { var target = this; var args = arguments; return setTimeout(function(){ fn.apply(target, args); }, interval); } return function() { if (timer) { clearTimeout(timer); } timer = delay.apply(this, arguments); } }; window.onresize = throttle(function(){ console.log('resize end'); }, 500);
如果在這一過程中事件被觸發(fā)則清除上一次事件句柄,重新綁定執(zhí)行時(shí)間。
參考資料:
《深入淺出node》
《Javascript設(shè)計(jì)模式與開發(fā)實(shí)踐》
相關(guān)文章
bootstrap實(shí)現(xiàn)嵌套模態(tài)框的實(shí)例代碼
這篇文章主要介紹了bootstrap實(shí)現(xiàn)嵌套模態(tài)框的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01javascript定時(shí)器的簡(jiǎn)單應(yīng)用示例【控制方塊移動(dòng)】
這篇文章主要介紹了javascript定時(shí)器的簡(jiǎn)單應(yīng)用,結(jié)合javascript事件觸發(fā)控制方塊移動(dòng)操作分析了javascript定時(shí)器使用相關(guān)操作技巧,需要的朋友可以參考下2019-06-06JS截取字符串 subStr()、substring()、slice() 方法示例詳解
這篇文章主要介紹了JS截取字符串 subStr()、substring()、slice() 方法,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01淺談javascript中call()、apply()、bind()的用法
一直對(duì)Javascript中的apply/call/bind的用法很模糊,恰好看到了這篇文章。對(duì)三者之間的區(qū)別與聯(lián)系算是有了比較清晰的認(rèn)識(shí)。這里記錄下來,分享給大家。2015-04-04