如何使用 TypeScript/JavaScript 中的函数式编程将元素推送到 Map 内的数组?

我刚刚开始了从 OOP 背景到学习 FP 的旅程,以及从编写普通 TypeScript(命令式?)迁移到功能 TypeScript 代码的过程。不幸的是,我已经在努力弄清楚如何将其更改为功能代码:


const foos: Map<

  string,

  Bar[]

> = new Map();


export const addBar = (

  key: string,

  bar: Bar

) => {

  const foo = foos.get(key);


  if (foo) {

    foo.push(bar);

  } else {

    foos.set(key, [bar]);

  }

};

我了解如何在数组上使用 .map .filter .concat ,但是如何处理包含数组的 Map 呢?


关于 foos Map 我猜 Map 本身需要是只读的,而且里面的 Bar 数组也是如此,所以 .set .push 是不可能的。但是,如果我不能在 Map 上调用 .set 因为它是只读的,那么使用 Map 是否有意义,或者我应该只使用一个对象?


如果没有可变性,如何将元素推送到 Map 值内的数组(或者如果键不存在,则使用数组创建一个新映射,如上面的代码中所示)?


这是否足够高效,因为我需要每隔几秒向数组添加一个新元素,每次发生更改时复制整个地图(包括其许多数组)的不可变方式不会比我执行得更糟吗?刚刚像您通常所做的那样对数组进行了变异?


哈士奇WWW
浏览 142回答 2
2回答

FFIVE

您根本无法使用本机Map,因为它仅提供命令式接口。您可以使用开源库,例如流行的 ImmutableJS。或者您可以编写自己的持久(不可变)数据结构。基本要求是您的数据结构提供的操作不会修改输入。相反,每个操作都会返回一个新的数据结构 -const PersistentMap =&nbsp; { create: () =>&nbsp; &nbsp; &nbsp; ({})&nbsp; , set: (t = {}, key, value) =>&nbsp; &nbsp; &nbsp; ({ ...t, [key]: value })&nbsp; &nbsp; &nbsp; // <-- immutable operation&nbsp; }我们首先看一张empty地图,一个set操作的结果,然后确保empty地图没有被修改——const empty =&nbsp; PersistentMap.create()console.log&nbsp; ( empty&nbsp; , PersistentMap.set(empty, "hello", "world")&nbsp; , empty&nbsp; )// {}// { hello: "world" }// {}现在让我们看一个新的中间状态,m1。每次我们看到set返回一个新的持久映射并且不修改输入 -const m1 =&nbsp; PersistentMap.set(empty, "hello", "earth")console.log&nbsp; ( m1&nbsp; , PersistentMap.set(m1, "stay", "inside")&nbsp; , m1&nbsp; )// { hello: "earth" }// { hello: "earth", stay: "inside" }// { hello: "earth" }现在回答你的问题,我们可以添加一个push操作到我们的PersitentMap- 我们只需要确保我们不修改输入。这是一种可能的实现-const PersistentMap =&nbsp; { // ...&nbsp; , push: (t = {}, key, value) =>&nbsp; &nbsp; &nbsp; PersistentMap.set&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // <-- immutable operation&nbsp; &nbsp; &nbsp; &nbsp; ( t&nbsp; &nbsp; &nbsp; &nbsp; , key&nbsp; &nbsp; &nbsp; &nbsp; , Array.isArray(t[key])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? [ ...t[key], value ] // <-- immutable operation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : [ value ]&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; }我们push在下面看到行动。请注意,m2也不会empty因此而改变 -const m2 =&nbsp; PersistentMap.push(empty, "fruits", "apple")console.log&nbsp; ( m2&nbsp; , PersistentMap.push(m2, "fruits", "peach")&nbsp; , m2&nbsp; , empty&nbsp; )// { fruits: [ "apple" ] }// { fruits: [ "apple", "peach" ] }// { fruits: [ "apple" ] }// {}展开下面的代码段以在您自己的浏览器中验证结果const PersistentMap =&nbsp; { create: () =>&nbsp; &nbsp; &nbsp; ({})&nbsp; , set: (t = {}, key, value) =>&nbsp; &nbsp; &nbsp; ({ ...t, [key]: value })&nbsp; , push: (t = {}, key, value) =>&nbsp; &nbsp; &nbsp; PersistentMap.set&nbsp; &nbsp; &nbsp; &nbsp; ( t&nbsp; &nbsp; &nbsp; &nbsp; , key&nbsp; &nbsp; &nbsp; &nbsp; , Array.isArray(t[key])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? [ ...t[key], value ]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : [ value ]&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; }const empty =&nbsp; PersistentMap.create()console.log&nbsp; ( empty&nbsp; , PersistentMap.set(empty, "hello", "world")&nbsp; , empty&nbsp; )// {}// { hello: "world" }// {}const m1 =&nbsp; PersistentMap.set(empty, "hello", "earth")console.log&nbsp; ( m1&nbsp; , PersistentMap.set(m1, "stay", "inside")&nbsp; , m1&nbsp; )// { hello: "earth" }// { hello: "earth", stay: "inside" }// { hello: "earth" }const m2 =&nbsp; PersistentMap.push(empty, "fruits", "apple")console.log&nbsp; ( m2&nbsp; , PersistentMap.push(m2, "fruits", "peach")&nbsp; , m2&nbsp; , empty&nbsp; )// { fruits: [ "apple" ] }// { fruits: [ "apple", "peach" ] }// { fruits: [ "apple" ] }// {}

Cats萌萌

我认为这取决于你想要达到的目标。如果您希望您的代码是可测试的,FP 并不总是意味着只需要编写函数,您仍然可以使用类,但是如果您有一段复杂的代码要单独测试,您可以导出该代码段进行测试,并且它看起来像这样:// types.tstype FooDis = Record<string, object[]>;// addBarToFoos.tsexport const addBarToFoos = (foos: FooDis) => (key: string, bar: object): FooDis {&nbsp; foos = {&nbsp; &nbsp; ...foos,&nbsp; &nbsp; [key]: [&nbsp; &nbsp; &nbsp; ...foos[key],&nbsp; &nbsp; &nbsp; bar&nbsp; &nbsp; ]&nbsp; };&nbsp; return foos;}// FooClass.ts&nbsp;export class FooClass {&nbsp; private foos: FooDis = {};&nbsp; addBar(key: string, bar: object) {&nbsp; &nbsp; this.foos = addBarToFoos(this.foos)(key, bar);&nbsp; }}这样,“复杂”方法可以在没有外部依赖的情况下单独测试,并且您有一个使用该方法的实现。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript