函数式编程入门理解

126 阅读2分钟

什么是函数式编程

函数式编程(Function Program)是一种编程范式或者编程风格,与其类似的还有面向对象编程

  • 面向对象的含义是:把现实世界的事物抽象成面向对象世界的类和对象。通过封装,继承多态来掩饰事物与事物之间的联系。
  • 函数式编程则是把现实世界的事物事物之间的联系抽象成到程序世界
    • 程序的本质:根据输入通过某种运算得到相应的输出,程序开发过程中会涉及很多有输入输出的函数
    • 函数式编程中的函数不是指程序中的函数(方法),而是数学中的映射关系,如:y = sin(x),x和y的关系就是函数
    • 纯函数相同的输入总会得到相同的输出
// 非函数式
let a = 1
let b = 2
let c = a + b
console.log(c)


//函数式
function add(a,b){
return a + b
}
let c = add(1,2)
console.log(c)

函数是一等公民

  • 函数可以存在变量

  • 函数可以作为参数

  • 函数可以作为返回值

  • 将函数赋给变量:


let func = function(){
    console.log('first-class function')
}
func()

高阶函数

什么是高阶函数

高阶函数:

  • 可以把函数作为参数传给另一个函数
  • 可以把函数作为另一个函数的返回结果

函数作为参数:

function forEach(array,fn){
    for(let i=0;i<array.length;i++){
        fn(array[i])
    }
}

function filter(array,fn){
    let res = []
    for(let i=0;i<array.length;i++){
       if(fn(array[i]))
       {
           res.push(array[i])
       }
    }
    return res
}

上面代码中将fn函数作为参数传给了forEachfilter函数,所以forEach函数是一个高阶函数。

函数作为返回值:

function makeFunction(){
    let msg = 'hello world'
    return function(){
        console.log(msg)
    }
}

//once函数,fn函数只会执行一次
function once(fn){
    let done = false
    return function (){
        if(!done)
        {
            done = true
            fn.apply(this,arguments)
        }
    }
}
//上面的once函数运用了`闭包`,将`done`存储在闭包里,所以无论调用了多少次once,fn只会执行一次

闭包

  • 闭包:函数和其周围的状态捆绑在一起形成闭包。
  • 可以在另一个作用域中调用一个函数的内部函数并且访问这个函数的内部成员
function out(){
    let msg = 'hello world'
    return function(){
        console.log(msg)
    }
}

const fn = out()
fn()  //hello world

由于外层函数被外部引用,所以外层函数执行完后不会被销毁,其内部变量可以保存

柯里化

概念:个人理解是将一个接收多个参数的函数转化为只接收部分参数,然后返回一个函数接受剩下的参数,称为函数的柯里化

作用:

  • 可以让函数变得更灵活,粒度更小
  • 可以把多元函数转化为一元函数,通过函数组合产生更强大的函数

实现一个柯里化函数

	function curry(fun){
		let argLengs = fun.length
		const fn = function(...args){
			if(args.length >= argLengs){ 
				return fun.apply(fun,args)
			}
			else{
				return function(){
					return fn(...args.concat([].slice.call(arguments)))
				}
			}
		}
		return fn
	}
    
    function sum(a,b,c)
    {
        return a + b + c
        }

    const sumCurry = curry(sum)

    let sumer =  sumCurry(1)(2)(3) 
    console.log(sumer)   //6
    

上面的curry是一个将函数柯里化的函数,sumCurry即被柯里化后的sum函数。

组合函数

  • 将多个函数作为参数,组合成一个新的函数
  • 避免洋葱代码,即多层的函数调用嵌套。

数据管道

  • 管道即函数,一个数据x从管道进入,从管道另一侧输出y。
  • 可以将一个长的管道(大的函数)拆分成若干短的管道(小的函数)
fn = compose(f1,f2,f3)
fn()

函数组合

如果一个函数要经过多个函数的处理才能得到结果,那么可以把中间过程的函数合并成一个函数。

  • 函数组合默认从右到左执行

一个简单的组合函数:

function compose(f,g){
   return function(x){
       return f(g(x))
   }
}

实现一个组合函数:

onst reverse = arr => arr.reverse()
const first = arr => arr[0]
const toUpper = s => s.toUpperCase()

	// 组合函数
	function compose(...args){
		return function(value){
			return args.reverse().reduce((count,fn) => {
				return fn(count)
			},value)
		}
	}
	}

function f2(){}
	
const a = compose(toUpper,first,reverse)
	
console.log(a(['asd','dsa','wqe']))   //WQE