Lodash 和 Ramda 之间的区别

Jos*_*rés 28 javascript lodash ramda.js

所以我一直在研究一些关于 JS 框架的知识。据我所知,两个最受欢迎和现代的图书馆是LodashRamda(对吗?)。

我看到了关于 Lodash 和 Underscore 的类似问题。然而,我没有看到任何与Lodash和Ramda相关的内容。老实说,我也找不到任何基准。

有什么区别?用例怎么样?哪一个更好?

Sco*_*yet 86

免责声明:我是 Ramda 的创始人和主要维护者之一,所以我确信这个答案会包含一些个人偏见。我会努力不让事情失控。

\n

概述

\n

关于这部分问题:

\n
\n

哪一个更好?

\n
\n

这里没有人可以明确回答这个问题。这取决于您的要求、您的历史、您的编程品味以及一百万个甚至更多的模糊因素。

\n

当然,我偏向 Ramda,但我仍然不会尝试告诉您哪一个更好。

\n

但两者之间在能力上存在显着重叠,并且在基本理念上存在显着差异。

\n

两者都是实用功能的抓包,功能之间很少或根本没有内聚力。也就是说,它们是而不是框架。他们根本不会尝试确定您如何编写或组织代码。

\n

它们有很多重叠。在当前的 305 个 lodash 函数和当前的 261 个 Ramda 函数中,有 103 个具有共享名称,并且几乎总是具有相似的用途。剩下的函数可能有一半可以在其他库中以不同的名称找到。

\n

一个简短的历史

\n

尽管之前有一些实验性函数库,但Underscore是将其中许多概念带入 Javascript 主流的库。它曾一度成为该领域无可争议的领导者。

\n

但其性能存在问题。最终lodash的创建很大程度上是为了尝试以更好的性能完成同样的事情。通过创建经典函数(如 )的自定义版本map,而不是默认使用 JS 引擎的内置函数,lodash 很快就超越了 Underscore。但它一开始是作为 Underscore 的简单替代品,并在很长一段时间内保持了这一焦点。

\n

Ramda创始人对 Reginald Braithwaite 的JavaScript Allong\xc3\xa9中的想法印象深刻,并创建了 Ramda 作为教育工具来帮助将这些想法转变为实用的库他们不太关注性能,而更多地关注干净的 API 和功能组合,以及不可变的数据和无副作用的编码。通过一系列奇怪的事件,它最终变得相当受欢迎。

\n

如今您已经很少听说 Underscore 了。它仍然在那里,并且仍然使用了相当多的时间,但你听不到太多嗡嗡声。对于大多数用户来说,lodash 很好地填补了这个空间。Ramda 增长很快,但似乎已经稳定在lodash下载量的 20-25% 左右。但这三个库的功能和使用量都在持续增长,Underscore 和 Ramda 的使用量大致相同,远低于 lodash。

\n

Lodash 有一次创建了一个版本,试图考虑 Ramda 的一些核心问题。我个人从未使用过lodash-fp,所以我无法评价它的成功程度。

\n

哲学

\n

洛达什

\n

Lodash 注重灵活性和性能。正如其创建者曾经描述的那样,它的重点是

\n
\n

为尽可能多的开发人员提供高质量的实用方法,重点关注一致性、兼容性、定制和性能。

\n
\n

虽然没有通用库可以像自定义编写的代码一样快,但 lodash 已经尽可能接近了。

\n

Lodash 非常灵活。我几年前写过

\n
\n

考虑 lodash\'s filter:它的集合接受数组、对象或字符串,回调接受函数、对象、字符串或什么都不接受,其thisArg. 您将 3 * 4 * 2 = 24 个功能合而为一!

\n
\n

拉姆达

\n

Ramda 不太关心性能,更关心简单干净的 API 设计。Ramda 的想法是,一个函数应该只做一件事,并且应该有一个清晰的接口。Ramda 的filter函数采用谓词函数和可过滤类型的对象,并返回该类型的另一个对象。(当然,这提出了什么构成可过滤类型的问题,但这是针对其文档的。)

\n

Ramda 的重点是使函数的组合变得简单,就像所有数据都是不可变的一样工作,并避免副作用。它还包含其他函数式编程问题,例如提供镜头和使用FantasyLand 规范的代数类型。

\n

主要差异

\n
    \n
  • Lodash(忽略 lodash-fp)函数大多首先获取数据,然后是那些对数据起作用的东西,有时后面是改变行为的可选参数。Ramda 将最不可能改变的论点放在前面,将最有可能改变的论点放在最后。这意味着在数据转换函数中数据是最后的。Ramda 完全避免了可选参数。

    \n
  • \n
  • Ramda 柯里化了它的所有函数,以及它返回给你的几乎所有函数。Lodash 有一个curry函数,但您需要显式调用它。这是 Ramda 函数组合思想的核心。

    \n
  • \n
  • Lodash 专注于引用相等。Ramda 注重价值平等。虽然这些是相似的:

    \n
    // lodash\n_.union ([1, 2, 3, 4, 5], [2, 3, 5, 7, 11]) //=> [1, 2, 3, 4, 5, 7, 11]\n_.intersection ([1, 2, 3, 4, 5], [2, 3, 5, 7, 11]) //=> [2, 3, 5]\n\n// Ramda\nR.union ([1, 2, 3, 4, 5], [2, 3, 5, 7, 11]) //=> [1, 2, 3, 4, 5, 7, 11]\nR.intersection ([1, 2, 3, 4, 5], [2, 3, 5, 7, 11]) //=> [2, 3, 5]\n
    Run Code Online (Sandbox Code Playgroud)\n

    它们的行为非常不同:

    \n
    // lodash\n_.union (\n  [{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 5}], \n  [{x: 2}, {x: 3}, {x: 5}, {x: 7}, {x: 11}]\n)\n//=> [{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 5}, {x: 2}, {x: 3}, {x: 5}, {x: 7}, {x: 11}]\n_.intersection (\n  [{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 5}], \n  [{x: 2}, {x: 3}, {x: 5}, {x: 7}, {x: 11}]\n) //=> []\n\n// Ramda\nR.union (\n  [{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 5}], \n  [{x: 2}, {x: 3}, {x: 5}, {x: 7}, {x: 11}]\n)\n//=> [{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 5}, {x: 7}, {x: 11}]\nR.intersection (\n  [{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 5}], \n  [{x: 2}, {x: 3}, {x: 5}, {x: 7}, {x: 11}]\n) //=> [x: 2}, {x: 3}, {x: 5}]\n
    Run Code Online (Sandbox Code Playgroud)\n

    这种差异是显着的。Ramda 的设计与功能系统更紧密地结合在一起,但只要涉及相等性检查,它就会付出很大的性能代价。对于此类任务,Lodash 可能比 Ramda 快两个数量级。

    \n
  • \n
  • Ramda 主要设计用于通过组合在短管道或长管道中构建函数。Lodash 主要设计用于使用命令式代码。您可以使用任一库来完成任一工作,但典型的 Ramda 代码可能如下所示

    \n
    const myFn = R.pipe (\n  R.fn1,\n  R.fn2 (\'arg1\', \'arg2\'),\n  R.fn3 (\'arg3\'),\n  R.fn4\n)\n
    Run Code Online (Sandbox Code Playgroud)\n

    等效的 lodash 代码可能如下所示

    \n
    const myFn = (x, y) => {\n  const var1 = _.fn1 (x, y)\n  const var2 = _.fn2 (var1, \'arg1\', \'arg2\')\n  const var3 = _.fn3 (var2, \'arg3\')\n  return _.fn4 (var3)\n}\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • Lodash 对性能的关注意味着它将为任务提供许多优化良好的功能。例如,Lodash 具有所有这些功能:, isArguments, isArray, isArrayBuffer, isArrayLike, isArrayLikeObject, isBoolean, isBuffer, isDate, isElement, isEqual, isEqualWith, isError, isFinite, isFunction, isInteger, isLength, isMap, isMatch, isMatchWith, isNaN, isNative, isNull, isNumber, isObject, isObjectLike, isPlainObject, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isUndefined, isWeakMapisWeakSet

    \n

    相比之下,Ramda 期望您为常用函数提供更多参数。它只有isisEmpty、 和isNil。但它可以is通过显式调用来处理\n几乎所有上述情况:is (Array, [1, 2, 3])或者通过部分应用来创建可重用函数const isArray = is (Array)

    \n
  • \n
\n

其中一些差异可能会在 lodash-fp 中消失。但我并没有真正意识到 lodash-fp 是景观的主要部分。对于 lodash 本身,我们可以看到这些库有很大不同。

\n

表现

\n

该问题询问了基准。据我所知,还没有全面的基准测试套件。有趣的是,除了涉及值相等与引用相等的问题外,lodash 在大多数任务上的速度似乎要快 10 - 20%。Ramda 不像 lodash 那样高度优化,但它是在编写时考虑到性能的,只要满足其他更基本的标准即可。

\n

在那些确实涉及值与引用相等的情况下,lodash 团队可以指出更高的速度,但 Ramda 团队可能会回应说,快速得到错误答案很难说是胜利。

\n

目标听众

\n

Underscore 帮助将函数式编程工具引入了 Javascript。它是一个通用实用程序库,专为任何想要提高工作效率的 JS 开发人员而设计。洛达什继承了这一重点。两者都是以开发人员人体工程学为中心焦点编写的。

\n

Ramda 的受众受到更多限制。它适合那些不仅想要从函数式编程中获取特定工具,而且还想要获取其更基本思想(例如函数纯度和数据不变性)的人。它既针对想要转向更加 FP 风格的 JS 开发人员,也针对那些想要以熟悉的方式使用 JS 的 FP 语言开发人员。它以简单性为中心焦点。

\n

概括

\n

这些库在功能上有很多重叠。但他们的设计、基本理念和开发人员经验却截然不同。

\n

如果您在它们之间进行选择,根据上述内容,有一个适合您的正确答案,但没有适合每个人的明确的最佳库。

\n

您还应该考虑是否需要一个。开发自己的可重用函数列表并不难,这些函数可以包含在任何需要它们的项目中。该平台的功能比这些库刚诞生时要强大得多。

\n

  • 使用`_.unionBy`和`_.intersectionBy`可以得到与`R.union`和`R.intersection`相同的答案 (3认同)
  • @foxiris:当然,Ramda 有 `unionWith` (不知道为什么缺少 `differenceWith`!)。因此“R .unionWith (R .identical)”应该与“_.union”具有相同的作用。区别在于图书馆的哲学将什么视为默认和期望的行为,而不是您可以用它们完成什么。 (2认同)