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