函數式編程的幾個概念

Function Programming

本篇文章是本身對於JavaScript函數式編程一書的讀書筆記。利用underscore框架介紹函數式編程幾個概念。

高階函數

1. 將函數做爲參數;
複製代碼
<!--repeatedly值版本-->
    function repeatedly(times,value){
        return _.map(_.range(times),()=>{ return value })
    }

    <!--repeatedly 函數版本-->

    function repeatedly(times,fun){
        return _.map(_.range(times),fun)
    }

    repeatedly(3,function(){
        return Math.floor(Math.random()*10+1)
    })
複製代碼

repeatedly是函數式編程的一個典型思惟,將值變成函數。java

2. 返回其餘函數的函數。
複製代碼

react和redux裏面用了大量的返回其餘函數的函數。包括高階組件,applyMiddleware函數。 Thunk函數也是一個返回其餘函數的函數。react

var Thunk = function(fn){
        return function(){
            var args = Array.prototype.slice.call(arguments);
            return function(callback){
                args.push(callback);
                return fn.apply.(this,args);
            }
        }
    }

    var readFileThunk = Thunk(fs.readFile);

    readFileThunk(fileA)(callback);
複製代碼

由函數構建函數

  1. 函數式的精華(dispatch函數);
function existy(x) {
        return x != null;
    }
    function doWhen(cond, action) {
        if (tructhy(cond))
            return action();
        else
            return undefined;
    }
    function invoker(NAME, METHOD) {
        return function (target) {
            if (!existy(target)) {
                alert('Must provide a target');
            }
            var targetMethod = target[NAME];
            var args = _.rest(arguments);
            return doWhen(existy(targetMethod) && METHOD === targetMethod, function () {
                return targetMethod.apply(target, args);
            });
        }
    }
    function dispatch() {
        var funs = _.toArray(arguments);
        var size = funs.length;

        return function (target) {
            var ret = undefined;
            var args = _.rest(arguments);
            for (var funIndex = 0; funIndex < size; funIndex++) {
                var fun = funs[funIndex];
                ret = fun.apply(fun,construct(target,args))
                if(existy(ret)) return ret;
            }
            
            if(existy(ret)) return ret;
        }
    }

    var str = dispatch(invoker('toString',Array.prototype.toString),invoker('toString',String.prototype.toString));
    console.log(str('a'));
    console.log(str(_.range(10)));
複製代碼

dispatch將多個invoker組合在一塊兒,造成多態函數,或根據不一樣的參數產生不一樣行爲的參數。 2. 柯里化。 對於每一個邏輯參數,柯里化函數會逐漸返回已配置好的函數,直到全部的參數用完。編程

function curry(fun){
    return function(firstArg){
        retun function(secondArg){
            return fun(firstArg,secondArg);
        }
    }
}
複製代碼
  1. 部分應用。 柯里化函數逐漸返回消耗參數的函數,直到全部的參數耗盡,然而部分應用函數是一個"部分執行",等待接收剩餘的參數當即執行的參數。
function partApply(f, x) {
  return function(y) {
    return f(x, y);
  }
}
複製代碼
  1. 經過組合端至端的拼接函數。 一個理想化的函數式程序是向函數流水線的一端輸送的一塊數據,從另外一端輸出一個全新的數據塊。 例如: !_isString(name);
  • _isString接收一個對象,並返回一個布爾值。
  • !接收一個布爾值,並返回一個布爾值。

_.compose函數從右往左執行。也就是說,最右邊的函數的結果會被送入其左側的函數,一個接一個。redux

function not(x){
    return !x;
}
var isntString = _.compose(not,_isString);
複製代碼

純度,不變性和更改政策。

  1. pure function
  • 其結果只能從它的參數的值來計算。
  • 不能依賴於能被外部操做改變的數據。
  • 不能改變外部狀態。 javaScript會致使不純的函數或方法如Date.now(),console.log(),this和全局變量。
  1. 數據的不可變性。(immutablejs);
function touchAndLog(touchFn) {
  let data = { key: 'value' };
  touchFn(data);
  console.log(data.key); // 猜猜會打印什麼?
}

複製代碼

在不查看 touchFn 的代碼的狀況下,由於不肯定它對 data 作了什麼,你是不可能知道會打印什麼(這不是廢話嗎)。但若是 data 是 Immutable 的呢,你能夠很確定的知道打印的是 value。bash

  1. 更改政策。 隨便拿到一個對象並改變它,更好的策略是把對象放入容器中,並更改容器。

基於流的編程。

  1. 惰性鏈。
function LazyChain(obj){
    this._calls = [];
    this._target = obj; 
}

LazyChain.prototype.invoke = function(methodName){
    var args = _.rest(arguments);
    this._calls.push(function(target){
        var meth = target[methodName];
        return meth.apply(target,args);
    })

    return this;
}


LazyChain.prototype.force = ()=>{
    return _.reduce(this._calls,function(target,thunk){
        return thunk(target);
    },this._target)
}

new LazyChain([1,2,3]).invoke('sort').force();

複製代碼
相關文章
相關標籤/搜索