51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

借助函数柯里化实现读取Markdown元数据

定义 {#定义}

柯里化(英语:Currying) 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

来源: 维基百科

说白了就是返回函数的函数,其实在开发过程中多半已经用过了,只是之前没有去了解过这个东西叫什么。

我认为,他还可以是被看为一种轻量级的面向对象。

示例 {#示例}

定义一个getAdder函数,返回一个adder

|-------------------------|---------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | function getAdder(n) { return m => n + m } const adder = getAdder(3) console.log(adder(4)) // 7 |

这便是一种柯里化的应用了。

实际问题 {#实际问题}

我在开发过程中遇到过这种需求,也就是你现在看到的页面,它是用markdown写成的,并且文件头部有一些元信息,即metadata,本质是一堆键值对,用来描述这个文件。比如当前文件的头部就是这样的:

|-------------------|----------------------------------------------------------------------------------------| | 1 2 3 4 5 | date: 2022-5-14 category: Learn tags: JS TS intro: 返回函数的函数,可以认为是轻量级面向对象 id: 11 |

我把这个结构抽象一下,改成下面这样:

|-------------|---------------------------| | 1 2 | foo: abc bar: def |

我们的需求就是读取出来这些键值对。

解决方案 {#解决方案}

|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function parser(metadata) { return key => { const prefix = key + ':' const data = metadata.find(s => s.startsWith(prefix)) return data.substring(prefix.length).trim() } } const parse = parser([ 'foo: abc', 'bar: def' ]) console.log(parse('foo')) // abc console.log(parse('bar')) // def |

可以看出,这里的parser函数就是保存了metadata这一变量内容并且重复使用。

针对于parser函数的执行效率,可以进行以下优化:

|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | function parser(metadata) { const map = new Map() for (const data of metadata) { const [key, value] = data.split(/\s*:\s*/) map.set(key, value) } return key => map.get(key) } |

这里提前把所有的键值对都保存下来了,到执行的时候只需要获取一下即可。

那么回到开头说的,他可以被看成一种轻量级的面向对象,所以说完全可以用到面向对象的方法实现这个功能:

|---------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Parser { metadata = new Map() constructor(metadata) { for (const data of metadata) { const [key, value] = data.split(/\s*:\s*/) this.metadata.set(key, value) } } parse(key) { return this.metadata.get(key) } } const metadata = [ 'foo: abc', 'bar: def' ] const parser = new Parser(metadata) console.log(parser.parse('foo')) // abc console.log(parser.parse('bar')) // def |

但是实际应用中还是通过柯里化的方法更简洁明了,这也正体现这JS这门语言的魅力: 提供多种解决手段,我们总能从中找到较优的解决方案。

赞(1)
未经允许不得转载:工具盒子 » 借助函数柯里化实现读取Markdown元数据