- 簡(jiǎn)述
- 無(wú)副作用(No Side Effects)
- 高階函數(shù)(High-Order Function)
- 柯里化(Currying)
- 閉包(Closure)
- 不可變(Immutable)
- 惰性計(jì)算(Lazy Evaluation)
- Monad
一等公民
? ? ? ?高階函數(shù)(High-Order Function)是函數(shù)式編程思維中的重要條件脊僚,而滿足該條件的編程語(yǔ)言則需要將函數(shù)作為該語(yǔ)言的一等公民來(lái)看待相叁。符合一等公民的條件是:
- 函數(shù)可以作為一種數(shù)據(jù)類型的值,賦值于一個(gè)變量;
- 函數(shù)可以作為參數(shù)增淹,在其他函數(shù)中進(jìn)行傳遞椿访;
- 函數(shù)可以作為返回值,在其他函數(shù)中返回虑润;
? ? ? ?將函數(shù)視作一等公民的語(yǔ)言有:JavaScript成玫、Golang、Python拳喻、Scala哭当、Lua、Lisp舞蔽、Scheme等荣病。同時(shí),有著越來(lái)越多的其他語(yǔ)言看上了函數(shù)式編程的出彩之處渗柿,以其特有的方式實(shí)現(xiàn)著符合自身編程方式的高階函數(shù)个盆。
函數(shù)類型
? ? ? ?在 JavaScript
中,函數(shù)是數(shù)據(jù)類型 object
的子類型——即是指一種對(duì)象類型朵栖。我們可以通過(guò) typeof
操作符檢測(cè)一個(gè)值是否是一個(gè)函數(shù)類型:
// 一個(gè)函數(shù)聲明
function foo(x){
return x + 10;
}
typeof foo; // 返回值:'function'
然而颊亮,實(shí)際上在 JavaScript
中,函數(shù)并非是基本的數(shù)據(jù)類型陨溅,函數(shù)隸屬于對(duì)象類型终惑。能夠使用 typeof
操作符進(jìn)行檢測(cè)僅僅是語(yǔ)言提供的便利:
// 聲明一個(gè) number 類型的變量
const n = 13;
// 一個(gè)函數(shù)聲明
function foo(x){
return x + 10;
}
typeof foo; // 結(jié)果:'function'
typeof n; // 結(jié)果:'number'
// 檢測(cè) n 所持有的值是否是對(duì)象
n instanceof Object; // 結(jié)果:false
// 檢測(cè) foo 所持有的值是否是對(duì)象
foo instanceof Function; // 結(jié)果:true
Function instanceof Object; // 結(jié)果:true
foo instanceof Object; // 結(jié)果:true
可見(jiàn),函數(shù)是一個(gè)隸屬于 Function
的對(duì)象门扇,而 Function
本身又隸屬于頂層 Object
雹有,是它的子對(duì)象。因此臼寄,一個(gè)函數(shù)的實(shí)例霸奕,也隸屬于 Object
,他們之間擁有間接的繼承關(guān)系吉拳。
? ? ? ?很多有 面向?qū)ο?/code> 經(jīng)驗(yàn)的同學(xué)可能會(huì)想质帅,實(shí)例化對(duì)象不是通過(guò)
new
關(guān)鍵字調(diào)用類的構(gòu)造函數(shù)來(lái)進(jìn)行的嗎?這個(gè)問(wèn)題很簡(jiǎn)單:拿 Java
例舉留攒,Java
中擁有字面量形式的對(duì)象聲明方式 String str = "I like Java!";
煤惩,聲明變量 str
的過(guò)程中實(shí)際上也構(gòu)建了一個(gè)字符串對(duì)象,并沒(méi)有顯式的使用關(guān)鍵字 new
炼邀。
? ? ? ?在 JavaScript
中魄揉,以字面量的方式構(gòu)建對(duì)象有很多種,比如:
// 數(shù)組字面量
const arr = [1, 2, 3];
// 對(duì)象字面量
const obj = {id : 'xx001'};
// 函數(shù)字面量
function foo(){} // 函數(shù)聲明
const bar = function(){} // 函數(shù)表達(dá)式
const baz = (x) => x + 3; // ES6提供的lambda表達(dá)式函數(shù)
函數(shù)入?yún)?/h3>
? ? ? ?由于函數(shù)也是一個(gè)對(duì)象拭宁,因此函數(shù)也可以作為其他函數(shù)的參數(shù)洛退,作為入?yún)ⅲ?/p>
// 一個(gè)函數(shù)聲明
const add2 = (x) => x + 2; // 參數(shù)x基礎(chǔ)上加2的函數(shù)
const sub2 = (x) => x - 2; // 參數(shù)x基礎(chǔ)上減2的函數(shù)
const result = (y, f) => y * f(y); // 參數(shù)y基礎(chǔ)上乘以 函數(shù)參數(shù)f 的運(yùn)算結(jié)果
result(4, add2); // 結(jié)果: 24
result(4, sub2); // 結(jié)果: 8
? ? ? ?在 JavaScript
內(nèi)置對(duì)象中票彪,也有非常多的函數(shù)入?yún)?shí)例,比如 Array.prototype.map
函數(shù)的簡(jiǎn)單實(shí)現(xiàn):
// 一個(gè)高仿的 Array.prototype.map 函數(shù)
const map = function(arr, f){
const t = [];
for(let i=0;i<arr.length; t.push(f(arr[i],i++,arr)));
return t;
}
// 聲明一個(gè)數(shù)組
const a1 = [1,2,3,4];
// map函數(shù)調(diào)用:參數(shù) f 所示為每一個(gè)值乘以3不狮,并且返回一個(gè)新數(shù)組
const a2 = map(a1, (e) => e*3); // 結(jié)果:[3, 6, 9, 12]
函數(shù)返回值
? ? ? ?函數(shù)可以作為參數(shù)降铸,當(dāng)然也可以作為返回值。作為返回值的函數(shù)摇零,常用于緩存上一個(gè)函數(shù)的執(zhí)行狀態(tài):
// 一個(gè)函數(shù)聲明
const add2 = (x) => x + 2; // 參數(shù)x基礎(chǔ)上加 2 的函數(shù)
const mul2 = (x) => x * 2; // 參數(shù)x基礎(chǔ)上乘以 2 的函數(shù)
// 該函數(shù)用于計(jì)算推掸,計(jì)算結(jié)果不會(huì)直接得出,而是緩存了用于計(jì)算的兩個(gè)函數(shù)
const calc = function(f1, f2){
return (y) => f1( f2(y) );
}
// 根據(jù)緩存順序不同驻仅,生成的新的函數(shù)執(zhí)行過(guò)程也不同
const c01 = calc(add2, mul2);
c01(3); // 結(jié)果: 8
const c02 = calc(mul2, add2);
c02(3); // 結(jié)果:10