- 函數(shù)式編程隨著 react 的流行收到越來越多的關(guān)注
- VUE3 也開始擁抱函數(shù)式編程
- 函數(shù)式編程可以拋棄 this
- 打包過程可以利用 tree-shaking 過濾無用的代碼
- 方便測試 方便并行處理
- 有很多庫使用函數(shù)式編程:
loadsh
underscore
ramda
函數(shù)式編程的概念
函數(shù)式編程可以認(rèn)為是一種編程規(guī)范之一翔悠,我們經(jīng)常聽說的編程范式還有面向?qū)ο缶幊?面向過程編程
面向?qū)ο缶幊痰乃季S方式:把現(xiàn)實(shí)生活中的事物抽象成程序世界的類和對(duì)象岂却,通過封裝/繼承和多態(tài)來演示事物事件的聯(lián)系
函數(shù)式編程的思維方式:把現(xiàn)實(shí)生活中的事物和事物之間的聯(lián)系抽象到程序的世界
- 函數(shù)式編程的函數(shù)不是指程序中的的函數(shù)(方法)磁椒,而是數(shù)學(xué)中的映射關(guān)系
- 相同的輸入要有相同的輸出
- 函數(shù)式編程用來表述數(shù)據(jù)之間的映射
// 非函數(shù)式
// 這是面向過程編程
let num1 = 2;
let num2 = 3;
let sum = num2 + num2;
// 函數(shù)式
function add(n1, n2) {
return n1 + n2;
}
let sum = add(2, 3);
函數(shù)是一等公民
- 函數(shù)可以存儲(chǔ)在變量中
- 函數(shù)可以作為參數(shù)
- 函數(shù)可以作為返回值
高階函數(shù)
- 可以把函數(shù)作為參數(shù)傳遞
- 函數(shù)可以作為返回值
閉包
從外部的作用域勾笆,我們可以訪問一個(gè)函數(shù)內(nèi)的函數(shù)方妖,一個(gè)函數(shù)內(nèi)容返回一個(gè)函數(shù)匣缘,并且返回的函數(shù)可以訪問上一層函數(shù)的變量
本質(zhì):函數(shù)在執(zhí)行的時(shí)候會(huì)放到一個(gè)執(zhí)行棧中窘哈,當(dāng)函數(shù)執(zhí)行完畢后會(huì)從執(zhí)行棧中移除,但是堆上的作用域成員因?yàn)楸煌獠恳秒嗜鳎圆荒鼙会尫盼废牛虼藘?nèi)部函數(shù)依然可以訪問外部函數(shù)的成員
柯里化
// 模擬函數(shù)柯里化原理
function curry(func) {
return function curried(...args) {
// 判斷實(shí)參和形參的個(gè)數(shù) 如果參數(shù)大于或者等于,那個(gè)直接執(zhí)行下面的返回函數(shù)把參數(shù)傳進(jìn)去
// 否則進(jìn)入判斷卫漫,把參數(shù)合并再傳入函數(shù)中菲饼,
if (args.length < func.length) {
return function () {
return curried(...args.concat(Array.from(arguments)));
};
}
return func(...args);
};
}
function getSum(a, b, c) {
return a + b + c;
}
const curried = curry(getSum);
console.log(curried(1, 2, 3));
console.log(curried(1)(2, 3));
總結(jié)
- 柯里化可以讓我們給函數(shù)傳遞較少的參數(shù)得到一個(gè)已經(jīng)記住的某個(gè)固定參數(shù)的新函數(shù)
- 這是一種對(duì)函數(shù)參數(shù)的緩存
- 讓函數(shù)變的更靈活,讓函數(shù)的粒度更小
- 可以把多元函數(shù)(指多個(gè)參數(shù))轉(zhuǎn)化成一元函數(shù)(指一個(gè)參數(shù))列赎,可以組合使用函數(shù)宏悦,使其產(chǎn)生強(qiáng)大的功能
函數(shù)組合
- 函數(shù)組合: 如果一個(gè)函數(shù)要經(jīng)過多個(gè)函數(shù)才能得帶最終值,這個(gè)時(shí)候可以把中間的過程函數(shù)合并成一個(gè)函數(shù)
- 函數(shù)就像是數(shù)據(jù)的管道包吝,函數(shù)組合就是把這些管道連接起來饼煞,讓數(shù)據(jù)穿過多個(gè)管道形成最終的結(jié)果
- 函數(shù)組合默認(rèn)的是從右向左執(zhí)行
let fn = compose(f1, f2, f3);
let b = fn(a);
// 執(zhí)行順序 f3 f2 f1
// 函數(shù)組合示例
function compose(f, g) {
return function (value) {
return f(g(value));
};
}
function reverse(array) {
return array.reverse();
}
function first(array) {
return array[0];
}
const last = compose(first, reverse);
console.log(last([1, 2, 3, 4])); // 4
// 模擬loadsh組合函數(shù)
function compose(...args) {
return function (value) {
return args.reverse().reduce(function (acc, fn) {
return fn(acc);
}, value);
};
}
// 精簡版
const compose = (...args) => (value) =>
args.reverse().reduce((acc, fn) => fn(acc), fn);
函數(shù)組合要滿足結(jié)合律
let a = compose(f, g, h);
let v = compose(compose(f, g), h) == compose(f, compose(g, h));
// 意思是我們可以把f和組合,也可以g 和 h組合 效果都是一樣的
函數(shù)組合怎么調(diào)式
const log = (v) => {
console.log(v);
return v;
};
function compose(f, g) {
return function (value) {
return f(g(value));
};
}
function reverse(array) {
return array.reverse();
}
function first(array) {
return array[0];
}
// log
const last = compose(first, log, reverse);
console.log(last([1, 2, 3, 4])); // 4
point Free
一種編碼風(fēng)格
- 不需要指明處理的數(shù)據(jù)
- 只需要合成運(yùn)算過程
- 需要定義一些輔助的基本運(yùn)算函數(shù)
// 代碼示例
// world wild web ==> W.W.W
const fp = require("loadsh/fp");
const firstLetterToUpper = fp.flowRight(
fp.join("."),
fp.map(fp.first),
fp.map(fp.toUpper),
fp.split("")
);
console.log(firstLetterToUpper("world wild web"));
函子
函子的作用就是:如何把函數(shù)的副作用控制在可控范圍內(nèi)诗越、異常處理砖瞧、異步操作等
函子相關(guān)文章 推薦閱讀 http://www.reibang.com/p/afbce25c18fb