如果使用 Ramda reduce 但使用 native 则 Jest 测试失败

Jest test fails if using Ramda reduce but passes with native

我注意到,如果我使用 ramda,有时我会在尝试为我正在导出的方法编写 Jest 测试时遇到问题。我已经将问题归结为以下测试和两个基本的减速器功能。我已将它们张贴在 gist 上,以免代码堵塞这个问题。

https://gist.github.com/beardedtim/99aabe3b08ba58037b20d65343ed9d20

我在使用 ramda reducer 时遇到以下错误:

      ● counter usage › counter counts the words and their index in the given list of words

    expect(received).toEqual(expected)

    Expected value to equal:
      [{"count": 3, "indexes": [0, 2, 4], "value": "a"}, {"count": 1, "indexes": [1], "value": "b"}, {"count": 1, "indexes": [3], "value": "c"}]
    Received:
      [{"count": 15, "indexes": [0, 2, 4, 0, 2, 4, 0, 2, 4, 0, 2, 4, 0, 2, 4], "value": "a"}, {"count": 5, "indexes": [1, 1, 1, 1, 1], "value": "b"}, {"count": 5, "indexes": [3, 3, 3, 3, 3
], "value": "c"}]

这让我相信 ramda 的 reduce 是保持某种状态或彼此共享 words。我不确定这是怎么回事。任何人都知道我应该用谷歌搜索什么或者其他 docs/examples 处理这个的人?

状态数组 (final) 硬连接到 reduceWithIndex。对此函数的所有调用共享同一个 final 数组。

试试这个:

import { reduce, addIndex } from 'ramda';

const reduceWithIndex = addIndex(reduce)((final, word, index) => {
  const found = final.find(({ value }) =>
    value.toLowerCase() === word.toLowerCase()
  );
  if (found) {
    found.count++;
    found.indexes.push(index);
  } else {
    final.push({
      value: word.toLocaleLowerCase(),
      count: 1,
      indexes: [index],
    });
  }

  return final;
});

export default words => reduceWithIndex([], words);

Thomas 的诊断非常准确。但我会选择一个稍微不同的修复:

import { reduce, addIndex, append } from 'ramda';

const reduceWithIndex = addIndex(reduce);

export default reduceWithIndex((final, word, index) => {
  const found = final.find(({ value }) =>
    value.toLowerCase() === word.toLowerCase()
  );
  if (found) {
    found.count++;
    found.indexes.push(index);
    return final;
  }
  return append({
      value: word.toLocaleLowerCase(),
      count: 1,
      indexes: [index],
  }, final);
}, []);

函数式编程涉及很多方面,但最重要的方面之一是不可变数据结构。尽管没有什么能阻止您改变累加器对象并将其传回您的 reducer 函数,但我发现它的风格很差。相反,总是 return 一个新对象,你不会有这样的问题。 Ramda 的所有功能都是基于这个原则构建的,所以当使用 append 时,你会自动得到一个新列表。

我还建议更改 if 块以避免 found 对象的内部突变。我会把它留作练习,但如果很难做到,请随时 ping。

你可以在 Ramda REPL 中看到 original solution and the altered version 之间的区别。