编程范式|青训营笔记

58 阅读3分钟

命令式

面向过程编程

面向过程(POP)是以过程为中心的编程思想。

它首先分析出问题的解决步骤,再按解决步骤设计对应的函数,最后按顺序调用这些函数从而解决整个问题。

面向过程编程的设计需要注重以下两个问题:

自顶向下:被调用的函数强调层次性,对复杂的问题分层次解决。

结构化编程:设计一个合理的逻辑结构,将解决问题的函数串联起来。

面向对象编程

面向对象(OOP)是以对象为中心的编程思想。

它首先对客观问题或事物抽象成一个类,然后调用类生成实例对象,通过实例对象的方法解决问题。

关于JavaScript面向对象编程,朋友们可以看我的往期文章:深入理解原型链与继承

面向对象的三个特性

封装:可以把属性和方法封装到一个类中,并且类与类之间是相互隔离的。

继承:子类可以继承父类的属性和方法,即派生类可以重用基类的属性和方法。

多态:多个对象可以共享相同的外部接口,通过不同的实例对象执行不同的行为。

面向对象的五个设计原则

单一职责原则(Single Responsibility Principle):软件模块应该有且只有一个改变的原因。

开放封闭原则(Open Close Principle):软件模块应该是可扩展,而不可修改的。

里氏替换原则(Liskov Substitution Principle):派生类(子类)对象可以在程式中代替其基类(超类)对象。

依赖倒置原则(Dependence Inversion Principle):程序要依赖于抽象接口,不要依赖于具体实现。

接口隔离原则(Interface Segregation Principle):一个类对另外一个类的依赖性应当是建立在最小的接口上。

声明式

函数式编程

函数式编程(FP)是以函数为中心的编程思想。

它通过把功能分解为一系列独立的函数,通过函数间相互调用来完成功能。

first class function:函数可以传递给其他变量或作为参数。

pure function:纯函数无副作用,不能影响外部状态。

currying:通过函数柯里化,能够支持惰性计算。

// 柯里化函数的原理:递归 + 闭包
function currying(fn, ...initArgs) {
    return function (...newArgs) {
        const args = [...initArgs, ...newArgs]
        return args.length === fn.length
            ? fn.apply(this, args)
            : currying.call(this, fn, ...args)
    }
}
// 测试用例
function test(a, b, c){
    return a + b + c
}
const add = currying(test)
console.log(add(1, 3, 5)) // 9
console.log(add(1, 3)(5)) // 9
console.log(add(1)(3, 5)) // 9
console.log(add(1)(3)(5)) // 9

composition:独立的函数经过组合实现特定的功能。

function compose(f, g) { 
    return function (x) { 
        return f(g(x))
    }
}
const g = (x) => x * 2
const f = (x) => x + 2
compose(f, g)(2)

functor:用于实现副作用可控

类:functor|方法:map()

class Functor {
    static of(value) {
        return new Functor(value)
    }
    constructor(value) {
        this.value = value
    }
    map(fn) {
        return Functor.of(fn(this.value))
    }
}
const container = Functor.of(2).map(x => x + 2)
console.log(container) // Functor { value: 4 }

monad:用于拍平嵌套的容器(函子)

类:monad|方法:join()、flatMap()

class Monad extends Functor {
    static of(value) {
        return new Monad(value)
    }
    constructor(value) {
        super(value)
    }
    join() {
        return this.value
    }
    map(fn) {
        return Monad.of(fn(this.value))
    }
    flatMap(fn) {
        return this.map(fn).join()
    }
}
// 嵌套的容器
const container_1 = Monad.of(2).map(x => Monad.of(x + 2))
console.log(container_1) // Functor { value: Functor { value: 4 } }
// 拍平后的容器(注意:仅能拍平两层嵌套的容器(函子))
const container_2 = Monad.of(2).flatMap(x => Monad.of(x + 2))
console.log(container_2) // Functor { value: 4 }

applicative:用于分别对两个容器进行取值

新增类:applicative|方法:ap()

class Applicative extends Functor {
    static of(value) {
        return new Applicative(value)
    }
    constructor(value) {
        super(value)
    }
    map(fn) {
        return Applicative.of(fn(this.value))
    }
    ap(other) {
        return other.map(this.value)
    }
}
// 注意:需要利用上述柯里化后的函数 add
const container_3 = Applicative.of(add(2))
    .ap(Applicative.of(2))
    .ap(Applicative.of(2))
console.log(container_3) // Functor { value: 6 }

响应式编程

响应式编程(RP)是一种面向数据流和变化传播的编程范式。