为什么我应该使用 immutablejs 而不是 object.freeze?

新手上路,请多包涵

我在网上研究了 immutablejs 超过 Object.freeze() 的好处,但没有发现任何令人满意的东西!

我的问题是,当我可以冻结一个普通的旧 javascript 对象时,为什么我应该使用这个库并使用非本机数据结构?

原文由 alisabzevari 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 289
2 个回答

我认为您不了解 immutablejs 提供的功能。它不是一个将你的对象变成不可变的库,它是一个处理不可变值的库。

无需简单地重复他们的 文档使命宣言,我将说明它提供的两件事:

  1. 类型。他们实现了(不可变的)无限范围、堆栈、有序集、列表……

  2. 它们的所有类型都实现为 持久数据结构

我撒谎了,这里引用他们的使命宣言:

不可变数据一旦创建就无法更改,从而使应用程序开发更加简单,无需防御性复制,并通过简单的逻辑实现高级记忆和更改检测技术。持久数据提供了一个可变的 API,它不会就地更新数据,而是总是产生新的更新数据。

我敦促您阅读它们链接到的文章和视频,以及更多关于持久数据结构的信息(因为它们是 immutablejs 核心),但我会用一句话总结:

假设您正在编写一个游戏,并且您有一个坐在二维平面上的玩家。例如,这里是 Bob:

 var player = {
  name: 'Bob',
  favouriteColor: 'moldy mustard',

  x: 4,
  y: 10
};

因为你喝了 FP koolaid 你想冻结玩家(brrr!希望 Bob 有一件毛衣):

 var player = Object.freeze({
    name: 'Bob',
    ...
});

现在进入你的游戏循环。在每一次滴答声中,玩家的位置都会改变。我们不能只更新播放器对象,因为它被冻结了,所以我们复制它:

 function movePlayer(player, newX, newY) {
    return Object.freeze(Object.assign({}, player, { x: newX, y: newY }));
}

这很好而且花花公子,但请注意我们进行了多少无用的复制:在每个滴答声中,我们创建一个新对象,迭代我们的一个对象,然后在它们之上分配一些新值。在每一个刻度上,在你的每一个物体上。那真是一口。

Immutable 为您总结了这一点:

 var player = Immutable.Map({
    name: 'Bob',
    ...
});

function movePlayer(player, newX, newY) {
    return player.set('x', newX).set('y', newY);
}

通过持久数据结构的ノ*✧゚魔力✧゚*ヽ,他们承诺 尽可能 减少操作量。

还有就是思维方式的差异。当使用“一个普通的旧 [frozen] javascript 对象”时,所有部分的默认操作 都是 假定可变性,并且您必须付出额外的努力才能实现有意义的不变性(也就是说承认该状态存在的不变性)。这就是 freeze 存在的部分原因:当你尝试不这样做时,事情就会恐慌。对于 Immutablejs,不变性当然是默认假设,并且在其之上有一个很好的 API。

这并不是说一切都是粉红色和玫瑰色,上面有樱桃。当然,任何事情都有它的缺点,你不应该仅仅因为你可以就到处塞进 Immutable。有时,只需 freeze 对象就足够了。哎呀,大多数时候这已经 足够 了。这是一个有用的库,有它的利基,只是不要被炒作冲昏了头脑。

原文由 Zirak 发布,翻译遵循 CC BY-SA 3.0 许可协议

根据我的 基准测试,immutable.js 针对写操作进行了优化,比 Object.assign() 更快,但是,它的读操作速度较慢。因此,决定取决于您的应用程序的类型及其读/写比率。以下是基准测试结果的摘要:

 -- Mutable
Total elapsed = 103 ms = 50 ms (read) + 53 ms (write).

-- Immutable (Object.assign)
Total elapsed = 2199 ms = 50 ms (read) + 2149 ms (write).

-- Immutable (immutable.js)
Total elapsed = 1690 ms = 638 ms (read) + 1052 ms (write).

-- Immutable (seamless-immutable)
Total elapsed = 91333 ms = 31 ms (read) + 91302 ms (write).

-- Immutable (immutable-assign (created by me))
Total elapsed = 2223 ms = 50 ms (read) + 2173 ms (write).

理想情况下,您应该在引入任何性能优化之前分析您的应用程序,但是,不变性是必须尽早决定的设计决策之一。当您开始使用 immutable.js 时,您需要在整个应用程序中使用它以获得性能优势,因为使用 fromJS() 和 toJS() 与普通 JS 对象进行互操作的成本非常高。

PS:刚刚发现深度冻结数组(1000 个元素)更新速度非常慢,大约慢 50 倍,因此您应该只在开发模式下使用深度冻结。基准测试结果:

 -- Immutable (Object.assign) + deep freeze
Total elapsed = 45903 ms = 96 ms (read) + 45807 ms (write).

原文由 engineforce 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题