函数式编程

121 阅读2分钟

1.纯函数的定义

函数在相同的输入时,产生相同的输出

函数在执行过程中,不产生副作用

比如触发事件,使用输出设备输出,或者更改输出值以外的物件的内容等等

什么是副作用呢?

side effect(副作用)表示在执行一个函数的时候,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储

纯函数在执行过程中就是不能产生这样的副作用,因为副作用往往是产生bug的温床

var names = ['zb', 'sh', 'ss']
    // var newArr = names.slice(0, 2)
    // slice本身就是一个纯函数,因为返回了一个新的数组,并没有改变原来的数组
    // slice 的实现
Array.prototype.zbslice = function(start, end) {
        fn = this
        let newArr = []
            // start = start || 0
        start = start === undefined ? 0 : start
            // end = end || fn.length
        end = end === undefined ? fn.length : end
        for (let i = start; i < end; i++) {
            newArr.push(fn[i])
        }
​
​
        return newArr
    }
    // console.log(newArr);
​
console.log(names.zbslice(0, 2));

2.js柯里化

是吧接受多个参数的函数u,变成接受一个单一的参数(最初函数的第一个参数)的函数,并且返回接收余下的参数,而且返回结果的新函数的技术

只传递给函数一部分的参数来调用它,让他返回一个函数去处理剩余的参数

这个过程就叫做柯里化

function sum(a, b, c, d) {
    return a + b + c + d
}
// 平常的调用是这样的
let sum1 = sum(10, 20, 30, 40)
console.log(sum1);
​
// 下面的样子就是函数柯里化
function s(a) {
    return function(b) {
        return function(c) {
            return function(d) {
                return a + b + c + d
            }
        }
    }
}
let res = s(10)(20)(30)(40)
console.log(res);

3.柯里化的作用

在函数式编程中,我们其实希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理过程交给一个函数来处理

那么我们是否就可以将每一次传入的参数在单一的函数中处理,处理完成以后在下一个函数中再次使用处理后的结果

也就是单一职责原则

// 下面的样子就是函数柯里化
function s(a) {
    a = a + 10
    return function(b) {
        b = b * 10
        return function(c) {
            c = c + 60
            return function(d) {
                return a + b + c + d
            }
        }
    }
}

4.柯里化的逻辑的复用

function log(date, type, message) {
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]: [${message}]`)
}
​
// 柯里化的优化
var log = date => type => message => {
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]: [${message}]`)
}
​
// 如果我现在打印的都是当前时间
var nowLog = log(new Date())
nowLog("DEBUG")("查找到轮播图的bug")
nowLog("FETURE")("新增了添加用户的功能")
//能发现要执行某一个函数的时候,不用每次传入三个参数,只需要在你需要的功能那块输出即可,详细见下面的代码
var nowAndDebugLog = log(new Date())("DEBUG")
nowAndDebugLog("查找到轮播图的bug")
nowAndDebugLog("查找到轮播图的bug")
nowAndDebugLog("查找到轮播图的bug")
nowAndDebugLog("查找到轮播图的bug")
​
​
var nowAndFetureLog = log(new Date())("FETURE")
owAndFetureLog("添加新功能~")
​

拿函数的参数个数有以下方法

function sum(a,b,c,d,e,f)
直接使用  sum.length 求出的就是sum函数的参数长度

5.组合函数

function double(num) {
  return num * 2
}
​
function square(num) {
  return num ** 2
}
​
var count = 10
var result = square(double(count))
console.log(result)
​
// 实现最简单的组合函数
function composeFn(m, n) {
  return function(count) {
    return n(m(count))
  }
}
​
var newFn = composeFn(double, square)
console.log(newFn(10))
​
​

6.实现组合函数

function zbCompose(...fns){
    var length = fns.length
    //先遍历传入的参数类型是否都是函数类型
    for(let i = 0; i < length;i++){
        if(typeof fns[i] !== 'function'){
            throw new TypeError('传入的参数不是函数类型')
        }
    }
    //  如果上面传入的参数都是函数的类型
    //  那么我们就开始
     function compose(...args){
         var index = 0
         let result = length ? fns[index].apply(this,args) : args
         while(++index < length){
             result = fns[index].call(this,result)
         }
         return result
     }
    return compose
}

\