我为什么要在object.freeze上使用immutablejs?

时间:2016-04-19 18:04:27

标签: javascript reactjs immutable.js

我已经在网上研究过immutablejs对Object.freeze()的好处,但没有找到令人满意的东西!

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

6 个答案:

答案 0 :(得分:47)

我认为你不明白immutablejs提供的东西。它不是一个只能将对象变为不可变的库,而是一个围绕使用不可变值的库。

如果不重复他们的docsmission statement,我会说明它提供的两件事:

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

  2. 所有类型都以Persistent Data Structures实现。

  3. 我说谎,这是他们的使命宣言的引用:

      

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

    我恳请您阅读他们链接的文章和视频以及有关持久性数据结构的更多信息(因为他们 的事物是不可变的事情是关于的),但我会在一个句子中总结一下:

    让我们假设你正在写一个游戏而你有一个位于二维飞机上的玩家。例如,Bob在这里:

    var player = {
      name: 'Bob',
      favouriteColor: 'moldy mustard',
    
      x: 4,
      y: 10
    };
    

    因为你喝FP koolaid你要冻结玩家(brrr!希望鲍勃得到一件毛衣):

    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);
    }
    

    通过持久数据结构的ノ*✧魔术✧゚* they,他们承诺尽可能少地进行 次操作。

    心态也存在差异。当使用“一个普通的[冻结的] javascript对象”时,所有部分的默认操作是假设可变性,并且你必须加倍努力以实现有意义的不变性(也就是说不变性)承认国家存在)。这是freeze存在的部分原因:当你试图做其他事情时,事情会引起恐慌。当然,使用Immutablejs不变性是默认假设,并且它有一个很好的API。

    这并不是说所有的粉红色和玫瑰色的樱桃都在上面。当然,一切都有它的缺点,你不应该因为你可以在任何地方填补Immutable。有时,仅freeze一个物体就足够了。哎呀,大部分时间更多比足够多。它是一个有用的图书馆,它有自己的利基,只是不要随便大肆宣传。

答案 1 :(得分:5)

根据我的benchmarks,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).

答案 2 :(得分:4)

它们都不会使对象深入不可变。

但是,使用Object.freeze,您必须自己创建对象/数组的新实例,并且它们不具有结构共享。因此,每一个需要深刻复制一切的变化,旧的集合都将被垃圾收集。

另一方面,

immutablejs将管理集合,当某些内容发生变化时,新实例将使用旧实例中未更改的部分,因此减少了复制和垃圾收集。

答案 3 :(得分:1)

Object.freeze本身没有做任何深度冻结,我相信immutable.js确实如此。

与任何库相同 - 为什么要使用下划线,jquery等等。

人们喜欢重新使用其他人建造的轮子: - )

答案 4 :(得分:1)

想到的最大原因 - 在具有帮助进行不可变更新的功能性api之外,是Immutable.js使用的结构共享。如果你有一个需要强制不变的应用程序(即你正在使用Redux),那么如果你只使用Object.freeze,那么你将为每个'变异'制作一个副本。随着时间的推移,这并不是真正有效,因为这将导致GC苛刻。使用Immutable.js,您可以获得结构共享(而不是必须实现自己的对象池/结构共享模型),因为从不可变的返回的数据结构是Tries。这意味着所有突变仍然在数据结构中被引用,因此GC捶打保持在最低限度。关于这一点的更多信息是关于Immutable.js的docsite(以及由创作者Lee Byron进行更深入的精彩视频):

https://facebook.github.io/immutable-js/

答案 5 :(得分:1)

Object.freeze()和immutable.js之间存在一些主要差异。

让我们先解决性能成本问题。 Object.freeze()很浅。它将使对象不可变,但所述对象内的嵌套属性和方法仍然可以变异。 Object.freeze() documentation解决了这个问题,甚至还提供了一个" deepFreeze"功能,在性能方面甚至更昂贵。另一方面,Immutable.js将使整个对象(嵌套属性,方法等)以较低的成本变得不可变。

此外,您是否需要克隆不可变变量Object.freeze()将强制您创建一个全新的变量,而Immutable.js可以重用现有的不可变变量来更有效地创建克隆。以下是this article

的有趣引用
  

"像.set()这样的不可变方法比克隆更有效   因为他们让新对象引用旧对象中的数据:仅   改变的属性不同。这样你就可以节省内存和   性能与不断深入克隆一切。"

简而言之,Immutable.js在新旧不可变变量之间建立逻辑连接,从而提高克隆性能和空间冻结变量占用内存。 Object.freeze()遗憾地没有 - 每次从冻结对象克隆一个新变量时,你基本上都会重新写入所有数据,并且两个不可变变量之间没有逻辑连接,即使(由于某些奇怪的原因)它们保持相同数据

因此,就性能而言,尤其是如果你不断在程序中使用不可变变量,Immutable.js是一个很好的选择。然而,性能并非一切,使用Immutable.js有一些重要的警告。 Immutable.js使用它自己的数据结构,这使得调试,甚至只是将数据记录到控制台,这是一种巨大的痛苦。它也可能导致基本JavaScript功能的丢失(例如,you cannot use ES6 de-structuring with it)Immutable.js文档很难被理解(因为它最初是为了在Facebook本身内部使用而编写的),需要大量的web - 即使出现简单问题也要进行研究。

我希望这涵盖两种方法中最重要的方面,并帮助您确定哪种方法最适合您。