函数式编程(学习笔记)
发布日期:2021-05-24 19:48:31 浏览次数:19 分类:精选文章

本文共 4262 字,大约阅读时间需要 14 分钟。

JavaScript 函数式编程笔记

函数式编程

函数式编程是一种编程思想,它与面向对象编程有著根本的不同。

  • 面向对象编程:将现实世界中的事物抽象成类和对象,通过封装、继承和多态来表现事物间的联系。
  • 函数式编程:将现实世界中的事物及其联系抽象到程序的层面,强调函数的映射关系而非直接的函数调用。

函数是一等公民

函数在函数式编程中被视为首等公民,它可以:

  • 作为变量使用
  • 作为参数传递
  • 作为返回值输出

这种特性使得函数式编程更加灵活和可构建性强。

高阶函数

高阶函数是一种能够将其他函数作为参数或返回值的函数。它们的优势在于可以简化代码逻辑,使代码更加简洁。

纯函数

纯函数的特点是:

  • 输入相同,输出相同。
  • 没有副作用。
    纯函数的优势体现在:
  • 缓存机制下性能提升
  • 测试更方便
  • 适合并行处理

柯里化

柯里化是一种将函数分解的方式:

  • 先传递部分固定参数,返回一个新的函数处理剩余参数。
    其优势包括:
  • 参数缓存
  • 增强灵活性
  • 函数粒度更小
  • 函数组合更加灵活
  • function curry(fn, args) {    const len = fn.length;    const initialArgs = Array.isArray(args) ? args.slice() : [];    return function() {        const currentArgs = initialArgs.concat(...Array.from(arguments));        if (currentArgs.length >= len) {            return fn.apply(this, currentArgs);        } else {            return curry.call(this, fn, currentArgs);        }    };}

    函数组合

    函数组合是一种将多个函数合并成一个函数的方式,其执行顺序为右到左。

    function compose(fn1, fn2) {    return function(value) {        return fn2(fn1(value));    };}

    点式编程

    点式编程是一种仅通过合成运算步骤定义数据处理过程,且不依赖于数据的特性。

    其核心是:

    • 数据操作过程与数据本身无关
    • 只关注运算步骤的组合

    例如:

    const f = flowRight(    replace(/\s+/g, "_"),    toLower)(Hello World); // world

    ##ny合偶

    Functors(函子)

    函子是一个容器,包含值以及对值进行变化的映射关系。它的核心是map方法。

    class Container {    constructor(value) {        this.value = value;    }    map(fn) {        return Container.of(fn(this.value));    }    static of(value) {        return new Container(value);    }}

    MayBe函子

    MayBe容器用来处理可能为空的值。

    class MayBe {    static of(value) {        return new MayBe(value);    }    constructor(value) {        this.value = value;    }    map(fn) {        return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this.value));    }    isNothing() {        return this.value === null || this.value === undefined;    }}

    Either函子

    Either容器用于处理或的情况,与if…else…类似,适合异常处理。

    class Left {    static of(value) {        return new Left(value);    }    constructor(value) {        this.value = value;    }    map(fn) {        return this;    }}class Right {    static of(value) {        return new Right(value);    }    constructor(value) {        this.value = value;    }    map(fn) {        return Right.of(fn(this.value));    }}function parseJson(str) {    try {        return Right.of(str);    } catch (e) {        return Left.of({ error: e.message });    }}const r = parseJson('{ name: zs }')    .map(x => x.name.toUpperCase());

    IO函子

    IO容器用于处理延迟执行的非纯操作,把不纯操作存储到值中。

    class IO {    static of(value) {        return new IO(function() {            return value;        });    }    constructor(fn) {        this.value = fn;    }    map(fn) {        return new IO(function(value) {            return fn(value);        }.flowRight(this.value));    }}

    Task异步执行

    通过folktale库实现简洁的异步操作:

    const { compose: ftCompose, curry: ftCurry } = require("folktale/core/lambda");const fs = require("fs");const { task } = require("folktale/concurrency/task");function readFile(filename) {    return task(resolver => {        fs.readFile(filename, "utf-8", (err, data) => {            if (err) {                resolver.reject(err);            }            resolver.resolve(data);        });    });}readFile("package.json")    .map(fp.split("\n"))    .map(fp.find(x => x.includes("version")))    .run()    .listen({        onRejected: err => {            console.log(err);        },        onResolved: value => {            console.log(value);        }    });

    Pointed函子

    Pointed函子通过of方法静态化创建容器,避免了原型链的使用。

    Monad函子

    Monad是Pointed函子的扩展,具备更强的灵活性和极限性。

    class IO {    static of(value) {        return new IO(function() {            return value;        });    }    constructor(fn) {        this.value = fn;    }    map(fn) {        return new IO(function(value) {            return fn(value);        }.flowRight(this.value));    }    join() {        return this.value();    }    flatMap(fn) {        return this.map(fn).join();    }}const readFile = function(filename) {    return new IO(function() {        return fs.readFileSync(filename, "utf-8");    });};const print = function(x) {    return new IO(function() {        console.log(x);        return x;    });};const cat = fp.flowRight(print, readFile);const r = cat("package.json")._value()._value();const r = readFile("package.json")    .flatMap(print)    .join();console.log(r);

    总结

    JavaScript的函数式编程强调函数的合成与铁律性,通过点式编程和函数组合能够实现更高效的代码构建。函数作为通用型态,能够在多种需求下灵活运用,使得代码更加简洁且具有Testable性。

    上一篇:112. 路径总和(Javascript)
    下一篇:reactive创建的响应式对象解构后为什么会失去响应式

    发表评论

    最新留言

    网站不错 人气很旺了 加油
    [***.192.178.218]2025年04月25日 23时12分23秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章