天天看點

js中的函數式程式設計

函數式程式設計

  • 前置知識
    • js 基礎
    • js面向對象

函數式程式設計含義

  • 函數式程式設計是一種強調以函數使用為主的軟體開發風格 ,也是一種範式。
  • 某些函數式程式設計語言Haskell、lisp、Scheme等。

js中函數式程式設計

  • 數學中的函數

    f(x) = y;

  • js中的函數
       let factor = 3;   let totalNum = num=>factor*num;   console.log( totalNum(3) );複制代碼      
  • 數學中的函數表達式相同的輸入,輸出是不變的,這就是函數程式設計的一個特性。将上面的js修改為符合函數式程式設計的規範如下。
       let totalNum = (num,factor)=>factor*num;   console.log( totalNum(3,3) );複制代碼      
  • js是多範式程式設計語言,但是函數作為一等公民,函數式程式設計具有天然優勢。

函數式程式設計中涉及到的概念

純函數

  • 函數式程式設計基于純函數
    let double = value=>value*2;複制代碼      
    • 純函數是對給定的輸入返還相同輸出的函數;例如
  • 純函數意義
    • 不依賴外部環境計算,不會産生副作用,提高函數的複用性。
      test('double(2) 等于 4', () => {
        expect(double(2)).toBe(4);
      })複制代碼      
    • 純函數可以産生可測試的代碼
    • 可讀性更強 ,js函數不管是否是純函數  都會有一個語義化的名稱,更便于閱讀。
    • 可以組裝成複雜任務的可能性。符合子產品化概念及單一職責原則。

高階函數

  • 高階函數定義
    • 高階函數:将函數作為參數或傳回函數的函數稱為高階函數(Higher-Order Function)。
  • 高階函數的抽象
    • 指令式循環(注重“如何”做,注重過程);
      let arr = [1,2,3];for(let i=0;i<arr.length;i++){console.log(arr[i]);
      }複制代碼      
    • 通過高階函數抽象過程,聲明式程式設計(注重做“什麼”,注重結果);
      const forEach = function(arr,fn){for(let i=0;i<arr.length;i++){
              fn(arr[i]);
          }
      }let arr = [1,2,3];
      forEach(arr,(item)=>{console.log(item);
      })複制代碼      
      上面通過高階函數 “forEach”來抽象循環"如何"做的邏輯,直接關注 做"什麼"
    • 一般高階函數用于抽象通用問題,簡而言之,高階函數就是定義抽象。
  • 高階函數的緩存特性
    • once 高階函數
    • 利用js函數的閉包
      const once = (fn)=>{let done = false;return function(){if(!done){
                  fn.apply(this,fn);
              }else{console.log("this fn is already execute");
              }
              done = true;
          }
      }    
      function test(){console.log("test...");
      }let myfn =  once(test);
      myfn();
      myfn();複制代碼      

柯裡化

  • 什麼是柯裡化?
    • 如下二進制函數
      let fn = (x,y)=>x+y;複制代碼      
    • 柯裡化函數
      const curry = function(fn){return function(x){return function(y){return fn(x,y);
              }
          }
      }let myfn = curry(fn);console.log( myfn(1)(2) );複制代碼      
    • 柯裡化是把一個多參數函數轉化成一個嵌套的一進制函數的過程;
  • 多參數函數柯裡化
    // 多參數柯裡化;const curry = function(fn){return function curriedFn(...args){if(args.length<fn.length){return function(){return curriedFn(...args.concat([...arguments]));
                    }
                }           return fn(...args);
            }
        }const fn = (x,y,z,a)=>x+y+z+a;const myfn = curry(fn);// console.log(myfn(1)(2));console.log(myfn(1)(2)(3)(1));複制代碼      
  • 柯裡化意義
    • 讓純函數更”純“,每次接受一個參數,松散解耦
    • 某些語言及特定環境下隻能接受一個參數

組合(composition)和管道(pipe)

組合(composition)

  • 組合函數:無需建立新的函數,通過基礎函數解決眼前問題。
    • 兩個個函數組合(緩存兩個函數,傳回新的函數,執行的時候按建立時的從右往左順序執行)
    • 多函數組合
      const compose = (...fns)=>val=>fns.reverse().reduce((acc,fn)=>fn(acc),val);複制代碼      
      let str = "Mamba Out,Mamba Never Out";const myfn = compose(oddOrEven,countFn,wordNum);console.log(myfn(str));複制代碼      
    • 擷取所有的單詞
      const wordNum = str=>str.match(/[\w\-]+/g);let str = "Mamba Out,Mamba Never Out";console.log(wordNum(str));複制代碼      
    • 統計長度
      const countFn = arr=>arr.length;複制代碼      
    • 判斷奇偶
      const oddOrEven = num=>num%2===0?"偶數":"奇數";複制代碼      
    • 組合函數使用:找到單詞統計長度最後判斷奇偶數
    • compose組合

      可以封裝組合函數來實作函數執行

      function afn(a){return a*2;
      }function bfn(b){return b*3;
      }const compose = (a,b)=>c=>a(b(c));let myfn =  compose(afn,bfn);console.log( myfn(2));複制代碼      

管道(pipe)

compose 執行是從右到左,pipe是從左至右的執行。函數如下:

const pipe = (...fns)=>val=>fns.reduce((acc,fn)=>fn(acc),val);複制代碼      

管道、組合 取舍 :管道及組合最大差別在于執行順序的不同,資料流向不同,達到目的是類似的。是以無優  劣之分,保持團隊風格統一就好了。

組合及管道的意義 把很多小函數組合起來完成更複雜的邏輯。

js函數式程式設計庫

js