一文帶你了解JavaScript函數(shù)柯里化
一、定義
柯里化(Currying)是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù),并且返回接受余下的參數(shù)且返回結(jié)果的新函數(shù)的技術(shù)。
通過一個簡單的例子解釋一下
function add(a, b) { return a + b } add(1, 2); // 3
將函數(shù)add轉(zhuǎn)化為柯里化函數(shù)_add:
function _add(a){ return function(b){ return a + b } } _add(1)(2); // 3
函數(shù)add和函數(shù)_add是等價的。
_add能夠處理add的所有剩余參數(shù),因此柯里化也被稱為部分求值。
實(shí)際上就是把add函數(shù)的a,b兩個參數(shù)變成了先用一個函數(shù)接收a然后返回一個函數(shù)去處理b參數(shù)。
現(xiàn)在思路應(yīng)該就比較清晰了:只傳遞給函數(shù)一部分參數(shù)來調(diào)用,讓它返回一個函數(shù)去處理剩下的參數(shù)。
二、柯里化函數(shù)的作用
1、參數(shù)復(fù)用
案例:拼接地址
按照普通思路去拼接一個地址
// 拼接地址 function getUrl(protocol, hostname, pathname) { return `${protocol}${hostname}${pathname}`; } const url1 = getUrl('https://', 'www.baidu.com', '/hasa'); const url2 = getUrl('https://', 'www.baidu.com', '/saandsa'); const url3 = getUrl('https://', 'www.baidu.com', '/hasak'); console.log(url1, url2, url3)
每次調(diào)用getUrl參數(shù)的時候都要重復(fù)的傳入?yún)?shù)'https://', 'www.baidu.com'。
柯里化封裝之后:
function curry(protocol) { return function (hostname, pathname) { return `${protocol}${hostname}${pathname}`; } } const url_curry = curry('https://'); const url1 = url_curry('www.baidu.com', '/hasa'); const url2 = url_curry('www.baidu.com', '/saandsa'); const url3 = url_curry('www.baidu.com', '/hasak'); console.log(url1, url2, url3)
很明顯,經(jīng)過柯里化封裝之后,之后再進(jìn)行地址拼接的時候,減少了參數(shù)個數(shù),降低了代碼重復(fù)率。
2、提前確認(rèn)
案例:兼容IE瀏覽器事件的監(jiān)聽方法(IE is dead)
傳統(tǒng)的方法:
/* * @param element Object DOM元素對象 * @param type String 事件類型 * @param listener Function 事件處理函數(shù) * @param useCapture Boolean 是否捕獲 */ var addEvent = function (element, type, listener, useCapture) { if (window.addEventListener) { element.addEventListener(type, function (e) { listener.call(element, e) }, useCapture) } else { element.attachEvent('on' + type, function (e) { listener.call(element, e) }) } }
缺陷就是,每次對DOM元素進(jìn)行事件綁定時都需要重新進(jìn)行判斷,其實(shí)對于事件監(jiān)聽網(wǎng)頁一發(fā)布瀏覽器已經(jīng)確定了,就可以知曉瀏覽器到底是需要哪一種監(jiān)聽方式。所以我們可以讓判斷只執(zhí)行一次。
柯里化封裝之后:
var curEvent = (function () { if (window.addEventListener) { return function (element, type, listener, useCapture) { // return funtion element.addEventListener(type, function () { listener.call(element) }, useCapture) } } else { return function (element, type, listener) { element.attachEvent('on' + type, function () { listener.call(element) }) } } }) var addEvent = curEvent(); addEvent(element, "click", listener)
立即執(zhí)行函數(shù),在觸發(fā)多次事件也依舊只會觸發(fā)一次if條件判斷。
3、延遲執(zhí)行
案例:釣魚統(tǒng)計重量
傳統(tǒng)的方法:
let fishWeight = 0; const addWeight = function(weight) { fishWeight += weight; }; addWeight(2.3); addWeight(6.5); addWeight(1.2); addWeight(2.5); console.log(fishWeight);
每次執(zhí)行addWeight方法時,都做了一次魚的體重的加和。
柯里化封裝后:
function curryWeight(fn) { let _fishWeight = []; return function () { if (arguments.length === 0) { return fn.apply(null, _fishWeight); } else { _fishWeight = _fishWeight.concat([...arguments]); } } } function addWeight() { let fishWeight = 0; for (let i = 0, len = arguments.length; i < len; i++) { fishWeight += arguments[i]; } return fishWeight; } const _addWeight = curryWeight(addWeight); _addWeight(6.5); _addWeight(1.2); _addWeight(2.3); _addWeight(2.5); console.log(_addWeight())
在執(zhí)行_addWeight方法時,并沒有做魚的體重的加和,之后在最后一次執(zhí)行_addWeight()時,才做了加和。做到了延遲執(zhí)行addWeight方法的效果。
三、柯里化函數(shù)的實(shí)現(xiàn)
function curry() { let args = [...arguments]; let inner = function () { args.push(...arguments); return inner; } // 核心內(nèi)容:隱式轉(zhuǎn)換,調(diào)用了內(nèi)部的toString inner.toString = function () { return args.reduce(function (pre, next) { return pre + next; }) } return inner; } const result = curry(1)(2); console.log(Number(result));
四、柯里化總結(jié)
函數(shù)的柯里化,需要依賴參數(shù)以及遞歸,通過拆分參數(shù)的方式,來調(diào)用一個多參數(shù)的函數(shù)方法,以達(dá)到減少代碼冗余,增加可讀性的目的。
性能方面:
- 存取arguments對象通常要比存取命名參數(shù)要慢一點(diǎn);
- 一些老版本的瀏覽器在arguments.length的實(shí)現(xiàn)上是相當(dāng)慢的;
- 使用fn.apply( … ) 和 fn.call( … )通常比直接調(diào)用fn( … ) 稍微慢點(diǎn);
- 創(chuàng)建大量嵌套作用域和閉包函數(shù)會帶來花銷,無論是在內(nèi)存還是速度上。
應(yīng)用場景:
- 減少重復(fù)傳遞不變的部分參數(shù);
- 將柯里化后的callback參數(shù)傳遞給其他函數(shù)。
到此這篇關(guān)于一文帶你了解JavaScript函數(shù)柯里化的文章就介紹到這了,更多相關(guān)JavaScript函數(shù)柯里化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js控制的回到頁面頂端goTop的代碼實(shí)現(xiàn)
在瀏覽網(wǎng)頁的時候應(yīng)該會經(jīng)常見到右下角有個【回到頂端】的懸浮東東,本文也要使用js實(shí)現(xiàn)一下,感興趣的朋友可以參考下哈,希望可以幫助到你2013-03-03Javascript中this關(guān)鍵字的一些小知識
這篇文章主要介紹了Javascript中this關(guān)鍵字的一些小知識,本文講解了this的隱性綁定、var that = this兩部份內(nèi)容,需要的朋友可以參考下2015-03-03JavaScript算法系列之快速排序(Quicksort)算法實(shí)例詳解
這篇文章主要介紹了JavaScript算法系列之快速排序(Quicksort)算法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-09-09javascript實(shí)現(xiàn)原生ajax的幾種方法介紹
項目中不需要加載jquery這種龐大的js插件要使用到ajax這種功能該如何辦呢?下面和大家分享幾種利用javascript實(shí)現(xiàn)原生ajax的方法2013-09-09JavaScript實(shí)現(xiàn)五種不同煙花特效
這篇文章主要給大家?guī)砦鍌€好看的基于 HTML+CSS+JS 的煙花特效,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)JavaScript有一定的幫助,需要的可以參考一下2022-01-01