js 函數式編程 淺談

來源:互聯網
上載者:User

js 函數式編程 淺談

js 函數式編程

函數式的思想, 就是不斷地用已有函數, 來組合出新的函數。

函數式編程具有五個鮮明的特點:

1. 函數是第一等公民
指的是函數與其他資料類型一樣,處於平等地位

2. 只用運算式,不用語句
運算式(expression)是一個單純的運算過程,總是有傳回值;
語句(statement)是執行某種操作,沒有傳回值。

3. 沒有副作用
指的是函數內部與外部互動(最典型的情況,就是修改全域變數的值),
產生運算以外的其他結果。

4. 不修改狀態
變數往往用來儲存狀態(state)。不修改變數,意味著狀態不能儲存在變數中,
函數式編程使用參數儲存狀態

5. 引用透明
指的是函數的運行不依賴於外部變數或狀態,只依賴於輸入的參數,任何時候只要參數相同,
引用函數所得到的傳回值總是相同的

函數式編程的意義:
1. 代碼簡潔,開發快速
2. 接近自然語言,易於理解
3. 更方便的代碼管理
4. 易於並發編程
5. 代碼的熱升級

---------------------分割線------------------------

在 JavaScript 中,函數本身為一種特殊對象,屬於頂層對象,
不依賴於任何其他的對象而存在,因此可以將函數作為傳出 / 傳入參數,
可以儲存在變數中,可以做一切其他對象可以做的事情。

自調用函數(遞迴--自己調用自己)實際上是高階函數的一種形式。

函數式編程樣本:

 

// 階乘的一般實現function factorial(n) {  if (n == 1) {    return 1;  } else {    return factorial(n - 1) * n;  }}// 階乘的函數式編程風格實現function mul(a, b){  return a*b; } function dec(x){  return x - 1; } function equal(a, b){  return a==b; } function factorial(n) {  if (equal(n, 1)) {    return 1;  } else {    return mul(n, factorial(dec(n)));  }}
---------------------分割線------------------------
函數柯裡化:
是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,
並且返回接受餘下的參數而且返回結果的新函數的技術。

我的理解就是需要反覆調用一個方法a(),它的參數中有一個參數在一定的狀況下的值不易改變,
每次調用都寫很多次未免太過麻煩,而且也體現不出來它描述和解決的一類問題,這種情況下,
為了避免這兩個問題,我們就將其中那個不容易改變的參數給固定下來,新產生一個函數來應對
這一類問題。
加法柯裡化的簡單實現:

 

 

//加法function adder(num) {    return function(x) {      return num + x;    }}var add5 = adder(5);var add6 = adder(6);console.log(add5(1));// 6console.log(add6(1));// 7
這裡的add5表示的函數可以解決基數為5的加法問題,只需要傳遞一個參數就可以了,
而不必像普通的加法函數那樣每次調用都必須添加兩個參數。
//計算m的n次方var powerOfN = function(n){    return function(m){        var res = 1;        for(var i = 0; i < n; ++i){            res *= m;        }        return res;    } ;};//按需產生var powerOf2 = powerOfN(2);var powerOf3 = powerOfN(3);//調用傳參console.log(powerOf2(3));console.log(powerOf3(2));
柯裡化通用實現:

 

 

function curry(fn) {    var args = [].slice.call(arguments, 1);    return function() {        var inargs = [].slice.call(arguments);        console.log(args.concat(inargs));        return fn.apply(null, args.concat(inargs));    }}function curry(fn) {    var args = [].slice.call(arguments, 1);    return function() {        var inargs = [].slice.call(arguments);        console.log(args.concat(inargs));        return fn.apply(null, args.concat(inargs));    }}function add(num1, num2) {    return num1 + num2;}var newAdd = curry(add, 5);console.log(newAdd(6));
柯裡化將降低了函數使用的普遍性,增加了使用的特異性,使用柯裡化需要認真識別
其使用的情境,在符合要求的地方使用,不然會顯得囉嗦,降低代碼的可讀性。
---------------------分割線------------------------
高階函數
高階函數即為對函數的進一步抽象,就是以其它函數為輸入,或者返回一個函數為輸出的函數。
高階函數最常見的應用如 map(映射), reduce(規約), forEach(遍曆), filter(過濾)等,
它們都是以傳入不同的函數來以不同的方式運算元組元。
簡單應用:

 

 

function foo(f, g) {  return function() {    return f.call(null, g.apply(null, arguments));    //return f(g.apply(null, arguments)); 也是可以的  }}var sum = function(x, y) {  return x + y;}var square = function(x) {  return x * x;}var squareofsum = foo(square, sum);squareofsum(2, 3);// 25
下面我們來看一下怎樣從過程式編程過渡到函數式編程的:

 

1>形式一

 

var sum = function(x, y) {  return x + y;}var square = function(x) {  return x * x;}function foo(){  return square( sum(2, 3) );}foo();// 25
2>形式二

 

 

var sum = function(x, y) {  return x + y;}var square = function(x) {  return x * x;}function foo(f, g){  return f( g(2, 3) );}foo(square, sum);// 25
3>形式三

 

 

var sum = function(x, y) {  return x + y;}var square = function(x) {  return x * x;}function foo(f, g){  return function(){    var num1 = arguments[0];    var num2 = arguments[1];    console.log(num1, num2);// 2 3    var temp = g(num1, num2);    console.log(temp);// 5    return f(temp);  };}var myfunc = foo(square, sum);myfunc(2, 3);// 25
4>形式四

 

 

var sum = function(x, y) {  return x + y;}var square = function(x) {  return x * x;}function foo(f, g){  return function(){    var temp = g.apply(null, arguments);    return f(temp);  };}var myfunc = foo(square, sum);myfunc(2, 3);// 25
最後的形式四就是我們想要得到的效果。

 

---------------------分割線------------------------
其他樣本:

1>

 

function foo(fn, array, value){  var res = array.map(function(ele){    return fn.apply(null, [ele].concat(value));  });  return res;}function add(x, y) {  return x + y;}function sub(x, y) {  return x - y;}console.log( foo(add, [1, 2, 3], 3) );// [4, 5, 6]console.log( foo(sub, [1, 2, 3], 3) );// [-2, -1, 0]

2>

 

 

function multicast(fn) {  return function (){    var pre = arguments[0];    var rest = arguments[1];    var ret = pre.map(function(ele) {      return fn.apply(this, [ele].concat(rest));    });    return ret;  }}function add(x, y) {  return x + y;}var newAdd = multicast(add);console.log(newAdd([1,2,3],3));// [4, 5, 6]function sub(x, y) {  return x - y;}var newSub = multicast(sub);console.log(newSub([1,2,3],3));// [-2, -1, 0]

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.