前端学习笔记

87 阅读4分钟

前端

函数式编程

编程模式

面向对象编程(OOP):把现实世界中的事物抽象成程序世界中的类和对象,通过封装、继承和多态来演示事物事件的联系。

面向过程编程:分析出解决问题需要的步骤,然后编写函数实现每个步骤,最后依次调用函数。

函数式编程(FP):把现实世界的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象)。

函数是一等公民

函数可以存储在变量中

函数作为参数

函数作为返回值

高级函数

可以把函数作为参数传递给另一个函数

可以把函数作为另一个函数的返回结果

闭包

定义:函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包

闭包本质::函数在执行的时候会放到一个执行栈上当函数执行完毕之后会从执行栈上移除,但是 堆上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问外部函数的成员。

 // 生成计算数字的多少次幂的函数
function makePower (power) {
return function (x) {
return Math.pow(x, power)
}
}
let power2 = makePower(2)
let power3 = makePower(3)

纯函数

定义:相同的输入永远会得到相同的输出,无可观察的副作用。

优点:

可缓存:因为纯函数对相同的输入始终有相同的结果,所以可以把纯函数的结果缓存起来。

const _ = require('lodash')
function getArea (r) {
return Math.PI * r * r
}
let getAreaWithMemory = _.memoize(getArea)
console.log(getAreaWithMemory(4))

可测试:纯函数让测试更方便

并行处理:在多线程环境下并行操作共享的内存数据很可能会出现意外情况,纯函数不需要访问共享的内存数据,所以在并行环境下可以任意运行纯函数 (Web Worker)。

柯里化

当一个函数有多个参数的时候先传递一部分参数调用它(这部分参数以后永远不变),然后返回一个新的函数接收剩余的参数,返回结果

总结:

柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数

    这是一种对函数参数的'缓存'
​
    让函数变的更灵活,让函数的粒度更小
​
    可以把多元函数转换成一元函数,可以组合使用函数产生强大的功能

函数组合

compose: 如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间 过程的函数合并成一个函数

特性:

函数就像是数据的管道,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终结果

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

// 组合函数
function compose (f, g) {
return function (x) {
return f(g(x))
}
}
function first (arr) {
return arr[0]
}
function reverse (arr) {
return arr.reverse()
}
// 从右到左运行
let last = compose(first, reverse)
console.log(last([1, 2, 3, 4]))

flow():从左到右运行

flowRight():从右到左运行

const _ = require('lodash')
const toUpper = s => s.toUpperCase()
const reverse = arr => arr.reverse()
const first = arr => arr[0]
const f = _.flowRight(toUpper, first, reverse)
console.log(f(['one', 'two', 'three']))

fp(Point Free):把数据处理的过程定义成与数据无关的合成运算,不需要用到代表数据的那个参 数,只要把简单的运算步骤合成到一起,在使用这种模式之前我们需要定义一些辅助的基本运算函数。

const f = fp.flowRight(fp.join('-'), fp.map(_.toLower), fp.split(' '))
// 非 Point Free 模式
// Hello World => hello_world
function f (word) {
return word.toLowerCase().replace(/\s+/g, '_');
}
// Point Free
const fp = require('lodash/fp')
const f = fp.flowRight(fp.replace(/\s+/g, '_'), fp.toLower)
console.log(f('Hello World'))

Functor(函子)

容器:包含值和值的变形关系(这个变形关系就是函数)

函子:是一个特殊的容器,通过一个普通的对象来实现,该对象具有 map 方法,map 方法可以运行一个函数对值进行处理(变形关系)

// 一个容器,包裹一个值
class Container {
    // of 静态方法,可以省略 new 关键字创建对象
    static of (value) {
        return new Container(value)
    }
    constructor (value) {
        this._value = value
    }
    // map 方法,传入变形关系,将容器里的每一个值映射到另一个容器
    map (fn) {
        return Container.of(fn(this._value))
    }
}
// 测试
Container.of(3)
.map(x => x + 2)
.map(x => x * x)

总结:

函数式编程的运算不直接操作值,而是由函子完成

函子就是一个实现了 map 契约的对象

我们可以把函子想象成一个盒子,这个盒子里封装了一个值

想要处理盒子中的值,我们需要给盒子的 map 方法传递一个处理值的函数(纯函数),由这 个函数来对值进行处理

最终 map 方法返回一个包含新值的盒子(函子)