亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

函數式編程入門實踐(一)

2024-05-06 16:50:09
字體:
來源:轉載
供稿:網友

在文章之前,先和大家講一下對于函數式編程(Functional Programming, aka. FP)的理解(下文我會用FP指代函數式編程):

  1. FP需要保證函數都是純凈的,既不依賴外部的狀態變量,也不產生副作用?;诖饲疤嵯拢敲醇兒瘮档慕M合與調用,在時間順序上就不會產生依賴,改變多個函數的調用順序也不必擔心產生問題,因此也會消滅許多潛在的bug。
  2. 函數必須有輸入輸出。如果一個函數缺乏輸入或輸出,那么它其實是一段處理程序procedure而已。
  3. 函數盡可能的保持功能的單一,如果一個函數做了多件事情,那么它理論上應當被拆分為多個函數。
  4. FP的意義之一就是,在適當的時機使用聲明式編程,抽象了程序流的控制與表現,從理解和維護的角度上會勝于命令式編程。
  5. FP是一種范式,但并不意味這和OOP(面向對象編程)沖突,兩者當然是可以和諧共存的。個人認為 React 其實就是一個很好的栗子~
  6. Javascript的函數一等公民以及閉包的特性,決定了Javascript的確是適合施展FP的舞臺

理解閉包

閉包對于 Javascript 來說,當然十分重要。然而對于函數式編程來說,這更加是必不可少的,必須掌握的概念,閉包的定義如下:

Closure is when a function remembers and accesses variables from outside of its own scope, even when that function is executed in a different scope.

相信大部分同學都對閉包有不錯的理解,但是由于對FP的學習十分重要。接下來我還是會啰嗦的帶大家過一遍。閉包就是能夠讀取其他函數內部變量的函數

簡單示例如下

// Closure demofunction cube(x) { let z = 1; return function larger(y) { return x * y * z++; };}const makeCube = cube(10);console.log(makeCube(5)); // 50console.log(makeCube(5)); // 100

那么有沒有想過在函數makeCube,或者也可以說是函數larger是怎么記住原本不屬于自己作用域的變量x和z的呢?在控制臺查看makeCube.prototype,點開會發現原來是有個[[Scopes]]這個內置屬性里的Closure(cube)記住了函數larger返回時記住的變量x和z。如果多嵌套幾層函數,也會發現多幾個Closure(name)在[[Scopes]]的Scopes[]數組里,按序查找變量。

函數式編程

再看下圖測試代碼:

function cube(x) { return function wrapper(y) { let z = 1; return function larger() {  return x * y * z++; }; }}const makeCubeY = cube(10);const makeCube = makeCubeY(5);const $__VAR1__ = '1. This var is just for test.';let $__VAR2__ = '2. This var is just for test.';var $__VAR3__ = '3. This var is just for test.';console.log(makeCubeY.prototype, makeCube.prototype);console.log(makeCube()); // 50console.log(makeCube()); // 100

打印makeCubeY.prototype:

函數式編程

打印makeCube.prototype:

 函數式編程

通過這幾個實驗可以從另一個角度去理解Javascript中閉包,一個閉包是怎么去查找不是自己作用域的變量呢?makeCube函數分別從[[Scopes]]中的Closure(wrapper)里找到變量y、z,Closure(cube)里找到變量x。至于全局let、const聲明的變量放在了Script里,全局var聲明的變量放在了Global里。

在學習FP前,理解閉包是尤為重要的~ 因為事實上大量的FP工具函數都使用了閉包這個特性。

工具函數

unary

const unary = fn => arg => fn(arg);

一元函數,應用于當只想在某個函數上傳遞一個參數情況下使用。嘗試考慮以下場景:

console.log(['1', '2', '3'].map(parseInt)); // [1, NaN, NaN]console.log(['1', '2', '3'].map(unary(parseInt))); // [1, 2, 3]

parseInt(string, radix)接收兩個參數,而map函數中接收的回調函數callback(currentValue[, index[, array]]),第二個參數是index,此時如果parseInt的使用就是錯誤的。當然除了Array.prototype.map,大量內置的數組方法中的回調函數中都不止傳遞一個參數,如果存在適用的只需要第一個參數的場景,unary函數就發揮了它的價值,無需修改函數,優雅簡潔地就接入了。(對于unary函數,fn就是閉包記憶的變量數據)

identity

const identity = v => v;

有同學會看到identity函數會覺得莫名其妙?是干嘛的?我第一眼看到也很迷惑?但是考慮以下場景:

console.log([false, 1, 2, 0, '5', true].filter( identity )); // [1, 2, "5", true]console.log([false, 0].some( identity )); // falseconsole.log([-2, 1, '3'].every( identity )); // true

怎么樣?眼前一亮吧,沒想到identity函數原來深藏不露,事實上雖然identity返回了原值,但是在這些函數中Javascript會對返回的值進行類型裝換,變成了布爾值。比如filter函數。我們可以看MDN定義filter描述如下(看標粗的那一句)。

filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true.

constant

const constant = v => () => v;

同樣,這個函數...乍一看,也不知道具體有什么用。但是考慮場景如下:

onst p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello!'); }, 200);});p1.then(() => 'Hi').then(console.log); // Hi!p1.then(constant('Hi')).then(console.log); // Hi!p1.then('Hi').then(console.log); // Hello!

由于Promise.prototype.then只接受函數,如果我僅僅只需要傳遞一個值時,那么constant便會提供這種便利。當然這個并沒有什么功能上的提升,但是的確提高了可閱讀性,也是函數式編程的一個優點。

spreadArgs & gatherArgs

const spreadArgs = fn => argsArr => fn( ...argsArr );const gatherArgs = fn => (...argsArr) => fn( argsArr );

嗯這兩個函數見名知義。分別用于展開一個函數的所有參數和收集一個函數所有參數,這兩個函數明顯對立,那么它們的應用場景又是什么呢?

spreadArgs函數示例如下:

function cube(x, y, z) { return x * y * z;}function make(fn, points) { return fn(points);}console.log(make(cube, [3, 4, 5])); // NaNconsole.log(make(spreadArgs(cube), [3, 4, 5])); // 60

gatherArgs函數示例如下:

function combineFirstTwo([v1, v2]) { return v1 + v2;}console.log([1, 2, 3, 4, 5].reduce(combineFirstTwo)); // Uncaught TypeErrorconsole.log([1, 2, 3, 4, 5].reduce(gatherArgs(combineFirstTwo))); // 15

看完以上代碼,簡單的兩個工具函數,輕易的做到了對一個函數的轉換,從而使其適用于另一個場景。如果從此應該可以瞥見函數式編程的一點點魅力,那么下面的兩個函數將給大家帶來更多的驚喜。

partial & curry

const partial = (fn, ...presetArgs) => (...laterArgs) => fn(...presetArgs, ...laterArgs); const curry = (fn, arity = fn.length, nextCurried) => (nextCurried = prevArgs => nextArg => { const args = [...prevArgs, nextArg]; if (args.length >= arity) {  return fn(...args); } else {  return nextCurried(args); } })([]);

相信大家對函數柯里化應該或多或少有點了解。維基百科定義:

在計算機科學中,柯里化(英語:Currying),又譯為卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。

當然得益于閉包的強大威力,柯里化這個武器得以誕生于Javascript世界。請大家先精讀以上關于partiel、curry函數的代碼。

喝一杯咖啡~

先模擬一個ajax函數如下:

function ajax(url, params, callback) { setTimeout(() => { callback(  `GET ${url} /nparams: ${params} /ndata: Hello! ${params} ` ); });}

考慮partial使用場景如下:

const fetchPerson = partial( ajax, "http://some.api/person" );fetchPerson('Teddy Bear', console.log);/*GET http://some.api/person params: Teddy Bear data: Hello! Teddy Bear */

考慮curry使用場景如下:

const fetchPerson = curry(ajax)('http://some.api/person');const fetchUncleBarney = fetchPerson('Uncle Barney');fetchUncleBarney(console.log);/*GET http://some.api/person params: Uncle Barney data: Hello! Uncle Barney */

partial和curry函數功能相似,但又有具體的不同應用場景,但總體來說curry會比partial更自動化一點。
但是!相信看完示例的同學又會有一連串問號?為什么好好地參數不一次性傳入,而非要分開多次傳入這么麻煩?原因如下:

  1. 最首要的原因是partial和curry函數都允許我們通過參數控制將一個函數的調用在時間和空間上分開了。傳統函數需要一次性將參數湊齊才能調用,但是有時候我們可以提前預置部分參數,在最終需要觸發此函數時,才將剩余參數傳入。這時候partial和curry就會變得十分有用。
  2. partial和curry的存在讓函數組合(compose)會更加便利。(函數組合也計劃之后和大家分享,這里就不詳細說了)。
  3. 當然最重要是也提升了可閱讀性!一開始可能不這么以為,但是如果你實踐操作感受之后,也許會改觀。

P.S. 關于函數式編程的實踐,大家可以使用lodash/fp模塊進行入門實踐。

一些思考
因為我也是函數式編程的初學者,如有不正確的地方,歡迎大家糾正~

接下來還是會繼續整理FP的學習資料,學習實踐,連載一些我對于函數式編程的學習與思考,希望和大家一起進步~

謝謝大家(●´∀`●)~

以上所述是小編給大家介紹的Javascript函數式編程詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97香蕉久久夜色精品国产| 成人www视频在线观看| 欧美性极品少妇精品网站| 精品偷拍一区二区三区在线看| 亚洲男人天堂网站| 日韩欧美中文字幕在线观看| 久久久伊人欧美| 91高清视频免费| 久久久视频精品| 91免费看视频.| 国产精品欧美一区二区三区奶水| 久久综合五月天| 欧美高清videos高潮hd| 亚洲欧美变态国产另类| 91高清在线免费观看| 韩日欧美一区二区| 欧美性受xxxx白人性爽| www.日韩欧美| 亚洲欧美国产一本综合首页| 欧美理论片在线观看| 在线丨暗呦小u女国产精品| 91免费视频网站| 欧美日韩在线影院| 国产精品一区二区久久久久| 日韩精品在线观看网站| 国产精品一区二区久久| 亚洲精品国产拍免费91在线| 中文字幕亚洲欧美在线| 欧美性xxxxxxx| 97成人精品视频在线观看| 久久九九精品99国产精品| 在线视频日本亚洲性| 亚洲偷熟乱区亚洲香蕉av| 欧美国产日韩免费| 国产女人18毛片水18精品| 国产亚洲精品久久久久久牛牛| 久久伊人精品一区二区三区| 亚洲午夜小视频| 中文字幕九色91在线| 另类色图亚洲色图| 日韩在线激情视频| 国产成人福利视频| 精品偷拍一区二区三区在线看| 国产精品影片在线观看| 一本色道久久88亚洲综合88| 不卡av日日日| 国产在线精品一区免费香蕉| 久久久亚洲精选| 国产一区二区日韩精品欧美精品| 亚洲第一免费播放区| 奇米4444一区二区三区| 亚洲第一黄色网| 性欧美长视频免费观看不卡| 欧美国产亚洲视频| 久久激情视频久久| 国产精品人人做人人爽| 国产精品一区二区久久久久| 亚洲片国产一区一级在线观看| 国产成人avxxxxx在线看| 国产精品旅馆在线| 欧美极品少妇与黑人| 欧美裸体男粗大视频在线观看| 亚洲日韩中文字幕在线播放| 日韩欧美有码在线| 麻豆乱码国产一区二区三区| 全色精品综合影院| 国产日韩在线播放| 91在线免费看网站| 欧美中文字幕在线视频| 日韩hd视频在线观看| 久久亚洲国产成人| 欧美一级片在线播放| 亚洲最新av网址| 亚洲自拍偷拍色图| 九九热这里只有精品免费看| 国产精品视频男人的天堂| 国产在线拍偷自揄拍精品| 91久久国产精品91久久性色| 欧美激情精品久久久久久大尺度| 69视频在线免费观看| 亚洲成人性视频| 尤物九九久久国产精品的特点| 91最新在线免费观看| 欧美一区二区三区图| 欧美成年人在线观看| 成人美女免费网站视频| 国产精品影院在线观看| 亚洲人午夜精品| 国产欧美在线看| 一区二区欧美亚洲| 欧美激情中文字幕乱码免费| 亚洲午夜女主播在线直播| 亚洲第一级黄色片| 亚洲一区二区少妇| 国产精品第3页| 日韩中文字幕视频| 欧美老女人xx| 日韩视频第一页| 国产噜噜噜噜噜久久久久久久久| 欧美日韩在线看| 久久久久久久久久久网站| 国产激情久久久久| 午夜精品蜜臀一区二区三区免费| 国产免费一区二区三区在线能观看| 日韩中文字幕第一页| 欧美日韩成人网| 在线看片第一页欧美| 91九色视频导航| 97视频在线免费观看| 亚洲美女视频网站| 奇米影视亚洲狠狠色| 久久福利视频网| 亚洲美女av在线| 日韩视频免费在线| 不卡av在线播放| 亚州精品天堂中文字幕| 欧美日韩亚洲视频| 97在线看免费观看视频在线观看| 国产精品a久久久久久| 亚洲一区第一页| 久久亚洲欧美日韩精品专区| 91欧美精品成人综合在线观看| 久久久亚洲影院你懂的| 国产精品永久在线| 538国产精品视频一区二区| 国产精品网站入口| 国产精品99久久久久久白浆小说| 这里只有精品视频在线| 日韩hd视频在线观看| 国产精品国产自产拍高清av水多| 国产中文日韩欧美| 亚洲精品综合精品自拍| 国产一区二区欧美日韩| 中文字幕日韩电影| 性色av一区二区三区红粉影视| 亚洲影院色无极综合| 久久精品视频导航| 国产精品激情av在线播放| 91丝袜美腿美女视频网站| 91最新国产视频| 亚洲男人天堂网| 国产成人亚洲综合91| 日本91av在线播放| 日韩精品视频免费| 精品视频在线导航| 麻豆国产精品va在线观看不卡| 亚洲成人网av| 日韩av观看网址| 欧美精品18videosex性欧美| y97精品国产97久久久久久| 欧美日韩国产区| 一本色道久久综合狠狠躁篇的优点| 久久久久久久久久亚洲| 亚洲无亚洲人成网站77777| 久久久伊人日本| 97免费视频在线播放| 日韩免费在线观看视频| 国产精品香蕉av| 成人久久18免费网站图片| 亚洲精品欧美极品| 国产美女91呻吟求| 超碰精品一区二区三区乱码| 亚洲一级一级97网| 色狠狠久久aa北条麻妃|