日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
淺談FunctionPrograming編程范式

背景

  • transform1 :input 一個(gè)字符串,output 要全部轉(zhuǎn)成大寫并尾部加感嘆號(hào)修飾;
  • transform2 :input 一個(gè)字符串,output 要全部轉(zhuǎn)成小寫并尾部加感嘆號(hào)修飾。

如果按以往命令式編程思維,可能會(huì)這么寫:

創(chuàng)新互聯(lián)建站專注于企業(yè)成都全網(wǎng)營(yíng)銷、網(wǎng)站重做改版、夏河網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5、成都做商城網(wǎng)站、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為夏河等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

const transform1 = (str) => {
if (typeof str === "string") {
return `${str.toUpperCase()}!`;
}
return "Not a string";
};

const transform2 = (str) => {
if (typeof str === "string") {
return `${str.toLowerCase()}!`;
}
return "Not a string";
};
transform1("hello world"); // "HELLO WORLD !"
transform2("HELLO WORLD"); // "hello world !"

兩個(gè)函數(shù)雖效果不同,但代碼框架極為相似,邏輯冗余且僵硬,比較難實(shí)現(xiàn)復(fù)用。相對(duì)而言,函數(shù)式編程思維則會(huì)盡量將邏輯抽象拆解為可被復(fù)用的若干最小單位,同樣的需求可能會(huì)這么實(shí)現(xiàn):

const { flow } = require("lodash/fp");
const toUpper = (str) => str.toUpperCase();
const toLower = (str) => str.toLowerCase();
const exclaim = (str) => `${str}!`;
const isString = (str) => (typeof str === "string" ? str : "Not a string");
const transform1 = flow(isString, toUpper, exclaim);
const transform2 = flow(isString, toLower, exclaim);
transform1("hello world"); // "HELLO WORLD !"
transform2("HELLO WORLD"); // "hello world !"

剛開始可能覺得沒什么必要,但是在中大型項(xiàng)目里尤其好用,因?yàn)槲覀円膊恢牢磥硇枨髸?huì)變得多復(fù)雜。FP 使用大量的Function,每個(gè)function都是一個(gè)單一的功能,再按功能需求以特定的方式組合起來,編寫時(shí)易于復(fù)用,在出現(xiàn)bug時(shí)也易于快速定位到相關(guān)的功能函數(shù),使得代碼減少重復(fù)、容易理解、容易改變、容易排除錯(cuò)誤和具有彈性。

核心概念

FP(Functional Programming)是一種通過簡(jiǎn)單地組合一組函數(shù)來編寫程序的風(fēng)格,它推薦我們將幾乎所有東西都包裝在函數(shù)中,編寫大量可重用的小函數(shù),然后簡(jiǎn)單地一個(gè)接一個(gè)地調(diào)用它們以獲得類似的結(jié)果:( func1.func2.func3 ) 或以組合方式,例如:func1(func2 (func3()))??偠灾牵阂环N抽象思維、一種編程風(fēng)格、一種編程規(guī)范。

FP 具有以下特點(diǎn):

1. Function 為First-class citizen(一等公民)

這個(gè)特性意味著函數(shù)與其他數(shù)據(jù)類型一樣,處于平等地位,可以賦值給其他變量,也可以作為參數(shù),傳入另一個(gè)函數(shù),或者作為別的函數(shù)的返回值,而 js 的function 本來就有這個(gè)特性。這也是 FP 得以實(shí)現(xiàn)的前提。

2. Declarative Programming(聲明式編程)

FP 是 Declarative Programming 的代表,邏輯為用較為抽象的程式碼,理解代碼想要達(dá)到怎樣的目標(biāo),F(xiàn)unction 之間不會(huì)互相共用state 狀態(tài)(著重 what)。而 Imperative Programming (命令式編程)比較容易寫出狀態(tài)互相依賴的代碼(著重how)。舉個(gè)加總 Array :

//Imperative 著重how一步步得出結(jié)果
var array = [3,2,1]
var total = 0
for( var i = 0 ; i <= array.length ; i ++ ){
total += array[i]
}

//OOP
//通過封裝把狀態(tài)(數(shù)據(jù))和行為(方法)內(nèi)聚到類中,對(duì)外提供能夠訪問或操作狀態(tài)的方法。
class Total {
constructor(numbers = []) {
this._numbers = numbers;
}
calc() {
const numbers = this._numbers;
let totle = 0;
for (let i = 0; i < numbers.length; i++) {
totle += numbers[i]
}
return totle;
}
}

const totle1 = new Totle([1, 2, 3, 4, 5]);
console.log(totle1.calc());//15
//Declarative 只需要知道 reduce 做了什么,不關(guān)心reduce是怎樣做的
var array = [3,2,1]
array.reduce( function( previous, current ){
return previous + current
})

3. 沒有Side Effect(副作用)

Side Effect:在完成函數(shù)主要功能之外完成的其他副要功能。會(huì)導(dǎo)致不易維護(hù)代碼、得到無法預(yù)期結(jié)果等等。而平常撰寫javaScript 容易造成的Side Effect 非常之多,例如:

修改外部的state

// 改了 global 變量
var a = 0;
a++;

const list = [{type:'香蕉',age:18},...];
// 修改 list 中的 type 和 age
list.map(item => {
item.type = 1;
item.age++;
})
  • 發(fā)送HTTP Request
  • Rendering screen
  • 使用會(huì)改變?cè)瓟?shù)組/變量的JS method (eg. splice)
  • 修改任何外部變量
  • DOM 操作
  • 讀取input 的值
  • Changing DB value
  • logging & console: 改變了系統(tǒng)狀態(tài)

4. Immutable data

所有的數(shù)據(jù)都是不可變的,這意味著如果想修改一個(gè)對(duì)象,那應(yīng)該創(chuàng)建一個(gè)新的對(duì)象用來修改,而不是修改已有的對(duì)象。

// mutable
const balls = ['basketball', 'volleyball', 'billiards']
balls[1] = 'Table Tennis'; // 改變數(shù)組原有項(xiàng)
balls // ['Table Tennis', 'volleyball', 'billiards']

// immutable
const balls = ['basketball', 'volleyball', 'billiards']
const newBalls = [...balls] // 復(fù)制一份
newBalls[1] = 'Table Tennis';
balls // ['basketball', 'volleyball', 'billiards'] 跟原本一樣
newBalls// ['Table Tennis', 'volleyball', 'billiards']

5. Stateless

對(duì)于一個(gè)函數(shù),完全不依賴外部狀態(tài)的變化

// Stateful
const x = 4;
x++; // x 變 5
// 省略 100 行...

x*2 // ??x是啥都忘了

//Stateless 不用擔(dān)心x是什么
const x = {
val: 0
};
const x1 = x => { val: x.val + 1};

6. Pure Function

遵守one input, one output 原則,不管輸入幾次同樣值,輸出結(jié)果永遠(yuǎn)相同,且永遠(yuǎn)有輸出值。只做運(yùn)算與返回return,而且不對(duì)外部世界造成任何改變( 沒有Side Effect)。Pure Function 里面data 多是immutable data 與stateless 的。另外當(dāng)一個(gè)函數(shù)是pure function 且不依賴任何外部狀態(tài)只依賴函數(shù)參數(shù),也稱作referential transparency (引用透明)。

//impure 有side effect
const add = (x, y) => {
console.log(`Adding ${x} ${y}`)
return x + y
}
//pure
const add = (x, y) => {
return {result: x + y, log: `Adding ${x} ${y}`}
}
//impure 當(dāng) n=4 沒有返回值
function tll(i){
if(i<3){
return 0
}
if(i>5){
return 1
}
}
//pure
function tll(i){
if(i<3){
return 0
}else{
return 1
}
}

//impure 相同輸入返回值不一樣
let x = 1
const count = ()=>x++
//pure
const count = (x)=>x+1

7. 柯理化拆分,「Composition」合成

柯理化的意義是將具有多個(gè)參數(shù)的多元函數(shù)轉(zhuǎn)化為具有較少參數(shù)的單元函數(shù)的過程。簡(jiǎn)單的柯理化函數(shù)是這樣的:

const curry = (fn, length = fn.length, ...args) =>
args.length >= length ? fn(...args) : curry.bind(null, fn, length, ...args);

柯理化的作用是可以固定參數(shù),降低函數(shù)通用性,提高函數(shù)的適合用性。舉個(gè):

// 假設(shè)一個(gè)通用的請(qǐng)求 APIconst request = (type, url, options) => ...
// GET 請(qǐng)求
request('GET', 'http://....')
// POST 請(qǐng)求
request('POST', 'http://....')

// 但是通過柯理化,我們可以抽出特定 type 的 request
const get = request('GET');
get('http://', {..})

Composition思維一般有兩種實(shí)現(xiàn)形式,一是compose:(fa,fb,fc)=>x=>fa(fb(fc(x))),一是pipe:(fa,fb,fc)=>x=>fc(fb(fa(x)))

compose函數(shù)的簡(jiǎn)單實(shí)現(xiàn):

function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}

if (funcs.length === 1) {
return funcs[0];
}

return funcs.reduce((a, b) => (...args) => a(b(...args)));
}

pipe 函數(shù)的實(shí)現(xiàn)同上不過改變一下執(zhí)行順序而已:

function pipe(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}

if (funcs.length === 1) {
return funcs[0];
}

return funcs.reduce((a, b) => (...args) => b(a(...args)));
}

舉一個(gè) lodash 與 lodash/fp 的介紹柯理化與 Composition 組合的意義:

//lodash實(shí)現(xiàn)對(duì)請(qǐng)求數(shù)據(jù)的處理 =>套娃(無柯理化)
const getIncompleteTaskSummaries = async function (memberName) {
let data = await fetchData();
return sortBy(
map(reject(filter(get(data, "tasks"), "username"), "complete"), (task) =>
pick(task, ["id", "dueDate", "title", "priority"])
),
"dueDate"
);
};

//lodash/fp 對(duì)FP有著更好的支持,包括完全柯理化、data-last等
const getIncompleteTaskSummaries = async function (memberName) {
let data = await fetchData();
return compose(
sortBy("dueDate"),
map(pick(["id", "dueDate", "title", "priority"])),
reject("complete"),
filter("username"),
get("tasks")
)(data);
};

可以看到經(jīng)過柯理化拆分提高函數(shù)適用性后,通過函數(shù)組合使得代碼如此的流暢、簡(jiǎn)潔。通過柯理化拆分和函數(shù)組合可以使得FP發(fā)揮很大的效用,也是FP必不可少的兩步操作,可以將柯理化后的函數(shù)比作加工站,函數(shù)組合比作流水線。

總結(jié)

lodash/fp、ramda都具備data-last、完全柯理化、組合函數(shù)、pure純函數(shù)等利于FP的特點(diǎn)。但相比之下兩者也有些差異:

  • lodash/fp依賴于lodash,是在lodash基礎(chǔ)上實(shí)現(xiàn)的對(duì)函數(shù)式編程的傾斜,好上手,但是受限于lodash,有很多局限性。ramda沒有前置依靠,完全FP,整個(gè)庫貫穿FP思想,但是上手成本高。
  • ramda具備很多邏輯判斷的函數(shù)(when,ifElse等),而lodash/fp暫無。
  • ramda有更友善的文檔,lodash/fp更多要與lodash進(jìn)行對(duì)照。

資料:

https://ramdajs.com/docs/

https://devdocs.io/lodash~4/index

https://github.com/lodash/lodash/wiki/FP-Guide


網(wǎng)頁名稱:淺談FunctionPrograming編程范式
標(biāo)題鏈接:http://www.dlmjj.cn/article/dhhcdei.html