摘要:有這樣的說法,并非柯里化有什么意義,而是,當函數可以作為函數的參數和返回值,成為函數式編程語言后,就會不可避免地產生函數柯里化。函數柯里化允許和鼓勵你分隔復雜功能變成更小更容易分析的部分。那么用函數柯里化就能實現提前返回。
#### 前言
在計算機科學中,柯里化(英語:Currying),又譯為卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。
#### 一、為什么會有函數柯里化?
Currying 的重要意義在于可以把函數完全變成「接受一個參數;返回一個值」的固定形式,這樣對于討論和優化會更加方便。
將關注的重點聚焦到函數本身,而不因冗余的數據參數分散注意力。
有這樣的說法,并非柯里化有什么意義,而是,當函數可以作為函數的參數和返回值,成為函數式編程語言后,就會不可避免地產生函數柯里化。
#### 二、具體實現
先來一個簡單的 add 函數
function add(x, y) { return x + y; } add(2, 3); // 5
重要的概念多說一遍:函數柯里化就是接收多個參數的函數變換為接收一個函數,并返回接收余下參數,最終能返回結果的技術
。
那么,繼續:
function add(x) { return function(y) { return x + y; } } add(2)(3); // 5
所以,曾經的一個函數,因為閉包操作(返回函數并訪問了自由變量的行為),變成了多個接收一個參數的函數。
所以簡單來講:函數柯里化就是意圖將函數的參數變成一個。讓函數可以輸入一個值,就返回一個相對應的值,從而實現純函數化。
為什么函數式編程要求函數必須是純的,不能有副作用?因為它是一種數學運算,原始目的就是求值,不做其他事情,否則就無法滿足函數運算法則了。在函數式編程中,函數就是一個管道(pipe)。這頭進去一個值,那頭就會出來一個新的值,沒有其他作用。
所以良好的編程規范是盡可能讓函數塊做一個事情,實現可復用性,可維護性。
上面的例子中,如果有很多個參數怎么辦,難道一層層嵌套?
我們繼續:
function plus(value) { "use strict"; var add = function () { var args = []; var adder = function adder() { Array.prototype.push.apply(args,Array.prototype.slice.apply(arguments)) return adder; } adder.toString = function () { return args.reduce(function(a, b) { return a + b; }) } return adder; } return add()(value); } plus(2)(3)(5).toString(); // 10;
上面的代碼看起來不那么優雅,如果是減法,我們就得又重新為減法寫這么多的代碼。像 lodash, underscore 這些工具庫,都提供了柯里化的工具函數。
我們一起來試著實現:
function curry(fn, args) { var length = fn.length; // 函數參數的長度 // 閉包保存參數列表 args = args || []; return function() { // 獲取參數列表。 var _args = args.slice(0); Array.prototype.push.apply(_args, Array.prototype.slice.call(arguments)) if (_args.length < length) { // 如果傳入的參數列表長度還沒有超過函數定義時的參數長度,就 push 新的參數到參數列表中保存起來。 // 自己調用自己,將保存的參數傳遞到下一個柯里化函數。 return curry.call(this, fn, _args); } else { // 如果傳入的參數列表長度已經超過函數定義時的參數長度,就執行。 return fn.apply(this, _args); } } }三、應用場景
函數柯里化的好處有幾個:
參數復用;
提前返回;
延遲計算/運行。
函數柯里化允許和鼓勵你分隔復雜功能變成更小更容易分析的部分。這些小的邏輯單元顯然是更容易理解和測試的,然后你的應用就會變成干凈而整潔的組合,由一些小單元組成的組合。
文章開篇的 add 函數,假如,每次調用加法有一個初始值會怎樣?
var add = curry(function(a, b, c) { return a + b + c; }) var addTen = add(10); var addSix = add(6); addTen(2)(3); // 15; addSix(7)(8); // 21;
以上代碼就實現了參數復用,保存固定參數的函數。
看一個經典的例子:
元素綁定事件監聽器:
var addEvent = function(el, type, fn, capture) { if (window.addEventListener) { el.addEventListener(type, function(e) { fn.call(el, e); }, capture); } else if (window.attachEvent) { el.attachEvent("on" + type, function(e) { fn.call(el, e); }); } };
以上代碼是為了兼容 IE 瀏覽器對 DOM 事件綁定做的函數封裝。
問題在于,每次對 DOM 元素進行事件綁定時,函數內部都會走一遍 if else。那么用函數柯里化就能實現提前返回。
var addEvent = (function(){ if (window.addEventListener) { return function(el, sType, fn, capture) { el.addEventListener(sType, function(e) { fn.call(el, e); }, (capture)); }; } else if (window.attachEvent) { return function(el, sType, fn, capture) { el.attachEvent("on" + sType, function(e) { fn.call(el, e); }); }; } })();總結
函數柯里化是“函數是一等公民”的編程語言環境形成的編程風格,利用了函數能作為參數一級返回值以及利用了閉包保存變量的特點,是將多個參數的函數轉換為接收一個參數,最后返回結果的技術。
歡迎關注我的個人公眾號“謝南波”,專注分享原創文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101449.html
摘要:里也有柯里化的實現,只是平時沒有在意。如果函數柯里化后雖然生搬硬套,不過現實業務也會有類似場景。 柯里化 先解釋下什么是 柯里化 在計算機科學中,柯里化(英語:Currying),又譯為卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。 js 里也有柯里化的實現,只是平時沒有在意。先把原文簡介貼...
摘要:專題系列共計篇,主要研究日常開發中一些功能點的實現,比如防抖節流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點是研究專題之函數組合專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現模式需求我們需要寫一個函數,輸入,返回。 JavaScript 專題之從零實現 jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實現一個 jQuery 的 ext...
摘要:一個經常會看到的函數的實現為第一版我們可以這樣使用或者或者已經有柯里化的感覺了,但是還沒有達到要求,不過我們可以把這個函數用作輔助函數,幫助我們寫真正的函數。 JavaScript 專題系列第十三篇,講解函數柯里化以及如何實現一個 curry 函數 定義 維基百科中對柯里化 (Currying) 的定義為: In mathematics and computer science, cu...
摘要:專題系列第十四篇,講解偏函數以及如何實現一個函數定義維基百科中對偏函數的定義為翻譯成中文在計算機科學中,局部應用是指固定一個函數的一些參數,然后產生另一個更小元的函數。 JavaScript 專題系列第十四篇,講解偏函數以及如何實現一個 partial 函數 定義 維基百科中對偏函數 (Partial application) 的定義為: In computer science, pa...
摘要:專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現模式需求我們需要寫一個函數,輸入,返回。這便是函數組合。 JavaScript 專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現 pointfree 模式 需求 我們需要寫一個函數,輸入 kevin,返回 HELLO, KEVIN。 嘗試 var toUpperCase = function(x) { return...
閱讀 3724·2021-10-13 09:39
閱讀 3789·2021-09-24 09:48
閱讀 1189·2021-09-01 10:30
閱讀 2526·2019-08-30 15:55
閱讀 1774·2019-08-29 16:39
閱讀 2296·2019-08-26 13:55
閱讀 3050·2019-08-26 12:23
閱讀 1634·2019-08-26 11:59