摘要:函數式接口之前在上看到一個技術視頻,講的接口為什么不好用,以及什么樣的接口更好用。演講者是的作者,他提出了一種全面函數式的接口設計模式。言歸正傳,今天聊聊這樣的接口如何實現,以及中的模塊。
函數式 js 接口
之前在 youtube 上看到一個技術視頻,講“underscore.js的接口為什么不好用”,以及什么樣的接口更好用。演講者是 lodash.js 的作者,他提出了一種“全面函數式”的 js 接口設計模式。大概類似這樣:
// 傳統接口 _.map([1, 2, 3], function (el) {return el * 2}); // return [2, 4, 6] // 函數式接口 var fn = _.map([1, 2, 3]); // return a function fn(function (el) {return el * 2}); // return [2, 4, 6]; // 或者 _.map([1, 2, 3])(function (el) {return el * 2}); // return [2, 4, 6];
找到一點感覺沒有?其實就是函數式編程語言中廣泛存在的“科里化”函數。當實參填滿形參表的時候,執行結算返回結果,否則返回一個臨時函數,繼續接受實參。
看到這個寫法眼前一亮,感覺有大規模簡化代碼的潛力。當時實際試了一下發下很多地方用不了,因為之前寫的代碼受 jQuery 影響,有很多這樣的接口:
foobar.attribute(name); // 讀屬性 foobar.attribute(name, newValue); // 寫屬性
這樣的接口是按照上述方法 curry 化會使得讀屬性變得不可能,根本原因是參數數量不同時 attribute 函數的語義根本不一樣。使用 jQuery 的時候感覺這種寫法非常爽,后來就跟著這么寫,但是目前看來這樣的接口設計是有問題的。
言歸正傳,今天聊聊這樣的接口如何實現,以及 lodash 中的 fp 模塊。
實現原理說到底就是個 currying 的問題,currying 在很多語言中是內置功能,但是 js 沒有,所以我們要實現一個 currying 工具函數。首先貼一個最簡易的 currying 實現,它的功能非常簡單,輸入一個函數 fn1 和部分實參,返回一個保存部分實參,繼續接收實參的函數 fn2,調用fn2,它會合并實參數組,并調用 fn1。
/** * 函數柯里化 * @param fn 輸入函數 * @return 柯里化后的函數 */ var curry = function (fn) { if (!isFunction(fn)) { return; } var args = slice(arguments, 1); return function () { return fn.apply(this, args.concat(slice(arguments, 0))); } }
isFunction 和 slice 大家都知道我就不貼了。看一下如何調用:
function add(a, b) { return a + b; } addOne = curry(add, 1); addOne(2); // return 3
有時候我們需要輸入的部分實參是數組列表形式,所以我們包裝一下剛才的 curry 函數:
/** * 函數柯里化 * @param fn 輸入函數 * @param arr 參數列表 * @return 柯里化后的函數 */ var curryApply = function (fn, arr) { if (!isFunction(fn)) { return; } var args = arr.slice(0); args.unshift(fn); return curry.apply(this, args); }
上面的 curry 函數有個問題,就是連續多次補充實參,我們還需要封裝一個支持連續調用的版本:
/** * 自動柯里化 * @param fn 輸入函數 * @param n 輸入函數參數個數 * @return 柯里化后的函數 */ var autoCurry = function (fn, n) { if (!isFunction(fn)) { return; } function retFn() { var len = arguments.length; var args = slice(arguments, 0); var nextn = n - len; if (nextn > 0) { return autoCurry(curryApply(retFn, args), nextn); } return fn.apply(this, args); } return retFn; }
autoCurry 使用的遞歸的方法,輸出函數可以可以通過簡單調用的方式連續補充實參,當實參和預設的參數數量相等時,執行輸入函數。使用方法如下:
function compute(a, b, c) { return (a + b) * c; } var curryedCompute = autoCurry(compute, 3); compute(1, 2, 3); // return 9 curryedCompute(1)(2)(3); // return 9
大家如果使用 node.js 的話,可能知道 npm 中有個 curry 模塊,實現的功能是一樣的,不同的是當你不輸入參數個數 n 時,curry 模塊 會使用 Function 對象的 length 屬性作為預設的 n 值。
lodash/fp到這里實現原理就講清楚了。本著不造輪子的原則,如果大家想嘗試一下函數式風格的基礎 js 庫的話,建議使用 lodash/fp 這個模塊。大家都知道 lodash 是 underscore 的 better implemention,而 lodash/fp 就是科里化的 lodash。與簡單的 currying 不同的是,為了方便使用,lodash/fp 的設計者調換了一些接口的參數順序,比如開頭提到的 _.map 接口,如果簡單 currying 的話第一個參數應該是數組[1, 2, 3],但是大多數時候,我們想要持有的是一個算法,用這個算法處理不同的數據。所以我們希望暫存的實際上是第二個參數 fn,所以 lodash/fp 的接口是這樣的:
// The `lodash/map` iteratee receives three arguments: // (value, index|key, collection) _.map(["6", "8", "10"], parseInt); // → [6, NaN, 2] // The `lodash/fp/map` iteratee is capped at one argument: // (value) fp.map(parseInt)(["6", "8", "10"]); // → [6, 8, 10]
關于 lodash/fp 更詳細的說明,請看:https://github.com/lodash/lodash/wiki/FP-Guide
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79724.html
摘要:為了盡可能提升互通性,已經成為函數式編程庫遵循的實際標準。與輕量級函數式編程的概念相反,它以火力全開的姿態進軍的函數式編程世界。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是 CSS 里最閃耀的一瞥;總結,...
摘要:本書主要探索函數式編程的核心思想。我們在中應用的僅僅是一套基本的函數式編程概念的子集。我稱之為輕量級函數式編程。通常來說,關于函數式編程的書籍都熱衷于拓展閱讀者的知識面,并企圖覆蓋更多的知識點。,本書統稱為函數式編程者。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 譯者團隊(排名不分先后)...
摘要:上傳圖片本地預覽功能靜態方法會創建一個,其中包含一個表示參數中給出的對象的。這個的生命周期和創建它的窗口中的綁定。這個新的對象表示指定的對象或對象。是對數組中每一項運行給定函數,如果該函數對任一項返回,則返回。 13、meta標簽的用法 http://www.alenqi.site/2018/03/04/complete-tags/ 14、隨機生...
摘要:函數通常是面向對象編程風格,具有副作用。因為在函數式編程中,很有可能這些引用指向的并不是同一個對象。記住,函數并不意味著函數式編程。函數可以用函數式編程風格編寫,避免副作用并不修改參數,但這并不保證。 軟件構建系列 原文鏈接:Functional Mixins 譯者注:在編程中,mixin 類似于一個固有名詞,可以理解為混合或混入,通常不進行直譯,本文也是同樣。 這是軟件構建系列教...
摘要:前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。背后的故事本文是對于年之間世界發生的大事件的詳細介紹,闡述了從提出到角力到流產的前世今生。 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎...
閱讀 2367·2021-11-22 14:56
閱讀 1175·2019-08-30 15:55
閱讀 3206·2019-08-29 13:29
閱讀 1354·2019-08-26 13:56
閱讀 3484·2019-08-26 13:37
閱讀 558·2019-08-26 13:33
閱讀 3349·2019-08-26 13:33
閱讀 2228·2019-08-26 13:33