新聞中心
小編收到小伙伴們要求,帶大家了解關(guān)于函數(shù)式編程,這個(gè)內(nèi)容想必大家并不陌生,也是經(jīng)常需要應(yīng)用的,已經(jīng)整理好以下詳細(xì)的介紹,一起來(lái)看看吧~

函數(shù)式編程理解:
編寫(xiě)代碼的時(shí)候,函數(shù)式編程更多的是從聲明式的方法,而傳統(tǒng)的編程更多的是命令式的方法。例如,上面的篩選學(xué)生年紀(jì),傳統(tǒng)的編程思想是,我創(chuàng)建了什么,我循環(huán)了什么,我判斷了什么,得出了什么結(jié)果;函數(shù)式編程的思想是,我聲明了一個(gè)篩選的函數(shù),我聲明了一個(gè)判斷的函數(shù),我把這兩個(gè)函數(shù)結(jié)合起來(lái),得出了一個(gè)結(jié)果。
關(guān)于純函數(shù)
在函數(shù)式編程的概念中,有一個(gè)重要的概念是純函數(shù),那么什么是純函數(shù)呢?
我們用代碼來(lái)解釋什么是純函數(shù):
const z = 10;
add(x, y) {
return x + y;
}
復(fù)制代碼
上面的add函數(shù)就是一個(gè)純函數(shù),它讀取x和y兩個(gè)參數(shù)的值,返回它們的和,并且不會(huì)受到全局的z變量的影響
把這個(gè)函數(shù)改一下
const z = 10;
add(x, y) {
return x + y + z;
}
復(fù)制代碼這個(gè)函數(shù)就變成了不純的函數(shù)了,因?yàn)樗祷氐闹禃?huì)受到全局的z的影響,換句話說(shuō),這個(gè)函數(shù)會(huì)被外部環(huán)境影響,我們就得出了第一個(gè)判斷是否純函數(shù)的重要依據(jù)——純函數(shù)不會(huì)受到外部環(huán)境的影響。
再用splice和slice來(lái)解釋一下:
var xs = [1,2,3,4,5]; // 純的 xs.slice(0,3); //=> [1,2,3] xs.slice(0,3); //=> [1,2,3] xs.slice(0,3); //=> [1,2,3] // 不純的 xs.splice(0,3); //=> [1,2,3] xs.splice(0,3); //=> [4,5] xs.splice(0,3); //=> [] 復(fù)制代碼
slice收到同樣的參數(shù),每次返回相同的值,所以是純函數(shù),splice收到同樣的參數(shù),每次返回不同的值,所以不是純函數(shù),我們就得出了第二個(gè)判斷是否純函數(shù)的重要依據(jù)——純函數(shù)相同的輸入,永遠(yuǎn)會(huì)得到相同的輸出。
總結(jié):
'純函數(shù)是這樣一種函數(shù),即相同的輸入,永遠(yuǎn)會(huì)得到相同的輸出,而且沒(méi)有任何可觀察的副作用' 復(fù)制代碼
關(guān)于柯里化
柯里化的概念很簡(jiǎn)單:只傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用它,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)。
const add = x => y => x + y; add(1)(2); // => 3 復(fù)制代碼
上面的例子,就是一個(gè)很典型的柯里化函數(shù),在我們第一調(diào)用的時(shí)候,接收了第一次傳入的參數(shù)(用閉包記?。?,返回了一個(gè)新的函數(shù);在第二次調(diào)用的時(shí)候,接收第二次傳入的參數(shù),并且和第一次傳入的函數(shù)相加,返回它們的和。
運(yùn)用上面的思想編寫(xiě)一個(gè)的柯里化函數(shù):
currying(fn, ...args1) {
// '判斷傳入的參數(shù)是否滿足傳入函數(shù)需要的參數(shù),比如說(shuō)add函數(shù)需要兩個(gè)參數(shù)相加,那么判斷是否傳入了兩個(gè)參數(shù),滿足調(diào)用傳入函數(shù)計(jì)算結(jié)果'
if (args1.length >= fn.length) {
console.log(args1, '--1--');
return fn(...args1);
}
// '不滿足返回一個(gè)新的函數(shù),繼續(xù)調(diào)用柯里化函數(shù),傳入保存的第一次傳入的函數(shù),傳入保存的第一次傳入的參數(shù),傳入第二次傳入的參數(shù),繼續(xù)上面的判斷邏輯,返回計(jì)算結(jié)果'
return (...args2) => {
console.log(args2, '--2--');
return currying(fn, ...args1, ...args2);
};
},
// 定義一個(gè)一般函數(shù)
const add = (x, y) => x + y;
// 使用
const increment = currying(add, 1);
console.log(increment(2));
const addTen = currying(add, 10);
console.log(addTen(2));
// => [2] --2--
// => [1,2] --1--
// => 3
// => [2] --2--
// => [10,2] --1--
// => 12
復(fù)制代碼柯里化函數(shù)比較重要的思想是:
多次判斷傳入的參數(shù)是否滿足計(jì)算需求,滿足,返回計(jì)算結(jié)果,如果不滿足,繼續(xù)返回一個(gè)新的柯里化函數(shù)
關(guān)于代碼組合
首先,先寫(xiě)一個(gè)簡(jiǎn)單的組合函數(shù):
const compose = (f, g) => x => f(g(x));
這個(gè)組合函數(shù)接收兩個(gè)函數(shù)當(dāng)作參數(shù),然后返回一個(gè)新的函數(shù),x是兩個(gè)函數(shù)之間都要使用的值,比如說(shuō):
const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
// 使用,實(shí)現(xiàn)一個(gè)功能,字符串變成大寫(xiě),加上個(gè)感嘆號(hào),還要截取一部分,再在前面加上注釋
const toUpperCase = x => x.toUpperCase();
const exclaim = x => `${x}!`;
const head = x => `slice is: ${x}`;
const reverse = x => x.slice(0, 7);
const shout = compose(exclaim, toUpperCase, head, reverse)
shout('my name is maya')
// => SLICE IS: MY NAME!
復(fù)制代碼組合的原理其實(shí)就是數(shù)學(xué)中的結(jié)合律:
(a + b) + c = a + (b + c)
對(duì)組合的理解是:
組合是什么,組合就是運(yùn)用了數(shù)學(xué)里的結(jié)合律,像是搭積木一樣,把不同的函數(shù)聯(lián)系起來(lái),讓數(shù)據(jù)在里面流動(dòng)
在各種庫(kù)里面都有組合的函數(shù),lodash,underscore,ramda等等,比如在underscore里面,組合是這樣的:
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
var args = arguments;
var start = args.length - 1;
return function() {
var i = start;
var result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result);
return result;
};
};
復(fù)制代碼相信大家到這里已經(jīng)初步了解了函數(shù)式編程的概念了,那么我們?cè)趺词褂煤瘮?shù)式編程的方式寫(xiě)代碼呢,舉個(gè)例子:
// 偽代碼,思路
// 比如說(shuō),我們請(qǐng)求后臺(tái)拿到了一個(gè)數(shù)據(jù),然后我們需要篩選幾次這個(gè)數(shù)據(jù), 取出里面的一部分,并且排序
// 數(shù)據(jù)
const res = {
status: 200,
data: [
{
id: xxx,
name: xxx,
time: xxx,
content: xxx,
created: xxx
},
...
]
}
// 封裝的請(qǐng)求函數(shù)
const http = xxx;
// '傳統(tǒng)寫(xiě)法是這樣的'
http.post
.then(res => 拿到數(shù)據(jù))
.then(res => 做出篩選)
.then(res => 做出篩選)
.then(res => 取出一部分)
.then(res => 排序)
// '函數(shù)式編程是這樣的'
// 聲明一個(gè)篩選函數(shù)
const a = curry()
// 聲明一個(gè)取出函數(shù)
const b = curry()
// 聲明一個(gè)排序函數(shù)
const c = curry()
// 組合起來(lái)
const shout = compose(c, b, a)
// 使用
shout(http.post)
復(fù)制代碼如果想要在項(xiàng)目里面正式使用函數(shù)式編程有這樣幾個(gè)步驟:
1、先嘗試使用ES6自帶的高階函數(shù)
2、熟悉了ES6自帶的高階函數(shù)后,可以自己嘗試寫(xiě)幾個(gè)高階函數(shù)
3、在這個(gè)過(guò)程中,盡量使用純函數(shù)編寫(xiě)代碼
4、對(duì)函數(shù)式編程有所了解之后,嘗試使用類(lèi)似ramda的庫(kù)來(lái)編寫(xiě)代碼
5、在使用ramda的過(guò)程中,可以嘗試研究它的源代碼
6、嘗試編寫(xiě)自己的庫(kù),柯里化函數(shù),組合函數(shù)等
以上就是關(guān)于函數(shù)式的全部?jī)?nèi)容介紹,大家可以消化學(xué)習(xí),如需了解更多python實(shí)用知識(shí),點(diǎn)擊進(jìn)入PyThon學(xué)習(xí)網(wǎng)教學(xué)中心。
新聞標(biāo)題:創(chuàng)新互聯(lián)Python教程:關(guān)于python函數(shù)式編程詳細(xì)介紹
標(biāo)題路徑:http://www.dlmjj.cn/article/djojdhs.html


咨詢
建站咨詢
