函数式编程

125 阅读3分钟

函数式

一、函数式编程的出现

  • 发展历程:命令(脚本)式 (面向过程) => 面向对象式(提高了模块的概念) => 函数式编程

1. url参数parse

  1. 数组在url中的展示形式

    location.search => '?name[]=progressive%coding&name[]=objective%coding&name[]=functional$%coding'

  2. 参数提取拼接成数组

['progressive%coding', 'objective%coding', 'objective%coding','functional%coding', 'functional$%coding' ]

  1. 手写方法,转换成数组对象

[{name:'Progressive Coding'},{name:'Objective Coding'},{name:'Functional Coding'}]

面向过程

    const _array = ['progressive$%coding', 'objective$%coding','functional$%coding' ]
    
    const _objArr=[];
    
    const nameParser = () =>{
        array.forEach(item=>{
            let names = item.split('$%');
            let newName = [];
            names.forEach(name=>{
                let nameItem =name[0].toUpperCase() + name.slice(1);
                newName.push(nameItem);
            })
            objArr.push({
                name:newName.join(' ');
            });
        })
        return objArr
    }
    console.log(nameParser(_array,_objArr));
    //存在问题:
    //1. 过程中存在逻辑包裹 - 需要看完整段代码才知道方法要干啥
    //2.存在临时变量,并且首位封闭迭代拓展难度高 

2. 解决方案

  1. 需求分析 => 从数组到数组对象的转换器 => 字符串转对象 nameParser => [objHelper :: string > object]
  2. 明确模块功能 => objHelper = formatName + assembleObj
  3. 功能拆分 => objHelper = [(split +capitalize + join)] + assembleObj

函数式

    const _array = ['progressive$%coding', 'objective$%coding','functional$%coding' ]
    const assembleObj = (key,x)=>{
        let obj = {};
        obj[key] = x;
        return obj;
    }
    const capitalize = name =>{ name[0].toUpperCase() + name.slice(1); }
    //组装描述
    const formatName =组装合并(join(''),map(capitalize),split('$%'));
    const objHelper = 组装合并(assembleObj('name'),formatName);
    const nameParser = map(objHelper)
    
    //使用
    nameParser(_array);
    

二、函数式编程的原理特征

1. 什么是函数式编程的原理?

  • 加法结合率|因式分解 | 完全平方公式 => a + b + c = (a + b) + c 原子组合的变化

2. 理论思想

a. 函数是一等公民:
1. 函数是逻辑功能实现的落脚点
2. 实现函数 + 函数拼接
b. 声明式编程
声明需求 => 语义化
c. 惰性执行 -无缝连接,性能节约
    let program = name =>{
        if(name === 'progressive'){
            return program =() =>{
                console.log('progressive')
            }
        }else if(name ==='objective'){
            return program =() =>{
                console.log('objective')
            }
        }else{
            return program =() =>{
                console.log('functional')
            }
        }
    }
    
    program('progressive')();//progressive
    program();//progressive  program第一次执行被提升,后续的操作都是第一次执行的结果

3. 无状态与副作用

  • a. 无状态 - 幂等;数据不可变 - 不可操作改变源数据
  • b. 无副作用 - 函数内部不应该直接对整个系统中任何参数变量做改动

三、实际开发

1. 纯函数改造

满足无状态和无副作用就是纯函数

    const _class = {
        name:'objective'
    }
    const score = str => _class.name + ':' + str;//函数内部引入外部变量后违反无状态的规则
    const changeClass = (obj,name) => obj.name = name;//修改了传入参数,违反无副作用
    changeClass(_class, 'functonal');
    score('100');
    
    //---------------------------------
    //改造
    const score = (obj, str) => obj.name + ':' +str;
     const changeClass = (obj,name) => ({...obj, name})
     

2. 流水线组装 - 加工 + 组装

a. 加工 - 柯里化

f(x,y,z) => f(x)(y)(z)

    const sum = (x,y)=>{
        return x + y; 
    }
    sum(1,2);
    
    //柯里化
    const add = x =>{
        return y =>{
            return x + y;
        }
    }
    add(1)(2);
    //实现体系 = 加工 + 组装,单个加工输入输出应当单值化
    
    const fetch = ajax(method,url,params);
    
    const request = ajax(method);
    const fetch = request(url);
    
    ajax(method)(url)(params)

可拆分传参的累加函数

  1. 构造柯里化结构
  2. 输入 处理外部的arguments => 类数组形态处理
  3. 传入参数无限拓展 => 递归 内层逻辑 => 返回函数
  4. 主功能实现 => 累加
  5. 输出
    const add = function(){
        //输入
        
        let args = Array.prototype.slice.call(arguments);
        
        //内层处理
        let inner = function(){
            args.push(...arguments);//内外层参数合并
            return inner;
        }
        inner.toString =function(){
            return args.reduce((prev,cur)=>{
                return prev + cur;
            })
        }
        return inner;
    }
    
    ''+add(1)(2)(3)(4)      // '10'
    parseInt((1)(2)(3)(4))   // 10
b. 流水线 - 组装函数
    const compose = (f,g) => x => f(g(x))
    const sum1 = x => x+1;
    const sum2 = x => x+2;
    
    const sum12 = compose(sum1,sum2);
    sum12(1)
  • 实际实现使用
    //命令式
    trim(reverse(toUpperCase(map(arr))))
    
    //面向对象
    arr.map().toUpperCase().reverse().trim();
    //函数式
    const result = compose(trim,reverse,toUpperCase,map);
    pipe(map,toUpperCase,reverse,trim);