javascript函數式編程入門小結

前言

最近花了很多時間接觸學習javascript的函數式的編程方式,然後爲了加深理解,又去折騰haskell。javascript

不一樣於人們比較熟悉的命令式編程,如面向對象編程(oop),函數式編程(fp)是一種更加抽象,更加‘數學’的編程方式。
固然,也是一種更加‘痛苦’的編程方式,尤爲是剛接觸時,老是難以擺脫的命令式的思惟方式,大腦回路老是會迷路。
不過幸運的是,javascript天生具有了函數式編程的基本元素,因此學習的起點不會過低。java

初接觸

第一個實例,函數式編程是如何作一個番茄炒雞蛋的。
僞代碼,對比oop:git

Class Chef{
  cook(m1,m2){
    return m1+m2
  }
}
chef = new Chef
food = chef.cook('番茄','雞蛋')
food //番茄炒蛋。

fp的方式github

getMaterial(m){
  return function(){
    return m
  }
}
cook(getM1,getM2){
  return getM1()+getM2()
}
food = cook(getMaterial('番茄'),getMaterial('雞蛋'));
food //番茄炒蛋

那麼如今,站在內存(擬做:你)變化的角度上,這二者的區別之處。
oop編程

1.你面前出現了一個廚師

2.你前面出現了番茄,雞蛋

3.廚師把番茄和雞蛋炒在一塊兒

4.廚師把番茄炒蛋裝在盤子上

4.你得到了番茄炒蛋

fp緩存

1.你拿一個空盤子,你決定弄點東西在上面

2.你面前出現了一個傳說中的廚具。 //沒錯!小當家同款廚具,只要丟材料進去,它就能弄出美味佳餚!

3.你雖然沒有材料,但幸運的是,你有兩張藏寶圖,分別標示了番茄和雞蛋的位置。經過藏寶圖,就能找到所需的材料。

4.你把兩張藏寶圖扔到廚具裏,告訴它,它得本身去找材料。 //傳說中的廚具就是這麼牛逼!

5.廚具得到了番茄

6.廚具得到了雞蛋

7.廚具終於炒了番茄和雞蛋

7.finally,你得到了番茄炒蛋

對比一下這個過程,能夠發現:數據結構

oop方式老是是在告訴系統,第一步應該幹什麼(搞個廚師)而後幹什麼(弄到番茄和雞蛋)、循序漸進,最後你就能獲得想要的值(番茄炒蛋)。函數式編程

fp方式呢,偏偏相反,它是惰性的。只有你須要什麼的時候,函數纔會運算,纔會返回數值,而不是一開始就存在的。函數

就好像學渣考90分,是由於在考試以前,他努力學習,到了90分。
這是結果。
而學霸考90分,只是由於考試的時候,作到90分時,懶癌發做,不想作題了。
這是過程。工具

fp的特性

這裏列舉了當前接觸到fp中編程思想中的幾個重要特性

1.不可變數據
2.函數是一等公民,即能做爲參數,也能夠是返回值
3.惰性求值

1.不可變數據

因爲fp中都是函數,爲了保證程序的可靠性,一樣的參數,傳入同一套的函數中,必須保證結果也是同樣的。如:

let o = {name:'zhouyg'};
r1 = fn1(fn2(fn3(o)))
r2 = fn1(fn2(fn3(o)))
r1 === r2 //true

在javascript中的因爲Array和Object的類型都是引用傳遞的。若是在函數內部改變了改變了原始o的值,那麼改變了原始o的值,那麼必然致使r1和r2的結果不同。致使程序不可靠,不可維護。
這是javascript的特性引發的,須要額外的手段補救。

每次傳遞Object和Array時候,都作一個拷貝,使用拷貝後的對象做爲函數參數

或者使用某些數據結構工具,例如F家著名的immutable.js

2.函數是一等公民

javascript自然知足,常見的各類回調。

3.惰性求值

顧名思義,只有在須要用到的纔去計算。這裏強行設定一種情景,如一個加法函數:
沒有惰性求值

function add(n1,n2){
  if(n1<5){
    return n1
  }else{
    return n1+n2
  }
}
result = add(add(1,2),add(3,4)) //至關於add(3,4)的計算是浪費的。
result//3

惰性求值

function add(n1,n2){
  return n1+n2;
}
function preAdd(n1,n2){
  return function(){
    return add(n1,n2)
  }
}
function doAdd(fn1,fn2){
  n = fn1()
  if(n<5){
    return n     //只須要運行fn1,獲得一個計算結果便可。
  }else{
    return add(fn1,fn2())
  }
}
result = doAdd(preAdd(1,2),preAdd(3,4))
result//10

對比一下可知,在javascript中的惰性求值,至關於先把參數先緩存着,return一個真正執行的計算的函數,等到須要結果採去執行。
這樣的好處在於比較節省計算,尤爲有時候這個在函數是不必定須要這個參數的時候。

最後

這裏只是簡單的回溯最近學習的fp的相關內容。並非爲了比較fp方式和其它編程方式的優劣,而是但願可以站在另外的一個角度,活躍大腦的思惟,開拓視野,以更豐富的姿式來解決問題,畢竟俗話說得好,姿式就是力量。

相關文章
相關標籤/搜索