ad4bca3143e2b04a861a051c3b47b5a39e2d27765fcf514908b955df59b0b1a5cb9dd124108156c62e9570651c025c4a9ae8bcb4a9bc7e794353b1bb2529bf 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. # Immutable collections for JavaScript
  2. [![Build Status](https://github.com/immutable-js/immutable-js/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/immutable-js/immutable-js/actions/workflows/ci.yml?query=branch%3Amain) [Chat on slack](https://immutable-js.slack.com)
  3. [Read the docs](https://immutable-js.com/docs/) and eat your vegetables.
  4. Docs are automatically generated from [README.md][] and [immutable.d.ts][].
  5. Please contribute! Also, don't miss the [wiki][] which contains articles on
  6. additional specific topics. Can't find something? Open an [issue][].
  7. **Table of contents:**
  8. - [Introduction](#introduction)
  9. - [Getting started](#getting-started)
  10. - [The case for Immutability](#the-case-for-immutability)
  11. - [JavaScript-first API](#javascript-first-api)
  12. - [Nested Structures](#nested-structures)
  13. - [Equality treats Collections as Values](#equality-treats-collections-as-values)
  14. - [Batching Mutations](#batching-mutations)
  15. - [Lazy Seq](#lazy-seq)
  16. - [Additional Tools and Resources](#additional-tools-and-resources)
  17. - [Contributing](#contributing)
  18. ## Introduction
  19. [Immutable][] data cannot be changed once created, leading to much simpler
  20. application development, no defensive copying, and enabling advanced memoization
  21. and change detection techniques with simple logic. [Persistent][] data presents
  22. a mutative API which does not update the data in-place, but instead always
  23. yields new updated data.
  24. Immutable.js provides many Persistent Immutable data structures including:
  25. `List`, `Stack`, `Map`, `OrderedMap`, `Set`, `OrderedSet` and `Record`.
  26. These data structures are highly efficient on modern JavaScript VMs by using
  27. structural sharing via [hash maps tries][] and [vector tries][] as popularized
  28. by Clojure and Scala, minimizing the need to copy or cache data.
  29. Immutable.js also provides a lazy `Seq`, allowing efficient
  30. chaining of collection methods like `map` and `filter` without creating
  31. intermediate representations. Create some `Seq` with `Range` and `Repeat`.
  32. Want to hear more? Watch the presentation about Immutable.js:
  33. [![Immutable Data and React](website/public/Immutable-Data-and-React-YouTube.png)](https://youtu.be/I7IdS-PbEgI)
  34. [README.md]: https://github.com/immutable-js/immutable-js/blob/main/README.md
  35. [immutable.d.ts]: https://github.com/immutable-js/immutable-js/blob/main/type-definitions/immutable.d.ts
  36. [wiki]: https://github.com/immutable-js/immutable-js/wiki
  37. [issue]: https://github.com/immutable-js/immutable-js/issues
  38. [Persistent]: https://en.wikipedia.org/wiki/Persistent_data_structure
  39. [Immutable]: https://en.wikipedia.org/wiki/Immutable_object
  40. [hash maps tries]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie
  41. [vector tries]: https://hypirion.com/musings/understanding-persistent-vector-pt-1
  42. ## Getting started
  43. Install `immutable` using npm.
  44. ```shell
  45. # using npm
  46. npm install immutable
  47. # using Yarn
  48. yarn add immutable
  49. # using pnpm
  50. pnpm add immutable
  51. # using Bun
  52. bun add immutable
  53. ```
  54. Then require it into any module.
  55. ```js
  56. import { Map } from 'immutable';
  57. const map1 = Map({ a: 1, b: 2, c: 3 });
  58. const map2 = map1.set('b', 50);
  59. map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50
  60. ```
  61. ### Browser
  62. Immutable.js has no dependencies, which makes it predictable to include in a Browser.
  63. It's highly recommended to use a module bundler like [webpack](https://webpack.js.org/),
  64. [rollup](https://rollupjs.org/), or
  65. [browserify](https://browserify.org/). The `immutable` npm module works
  66. without any additional consideration. All examples throughout the documentation
  67. will assume use of this kind of tool.
  68. Alternatively, Immutable.js may be directly included as a script tag. Download
  69. or link to a CDN such as [CDNJS](https://cdnjs.com/libraries/immutable)
  70. or [jsDelivr](https://www.jsdelivr.com/package/npm/immutable).
  71. Use a script tag to directly add `Immutable` to the global scope:
  72. ```html
  73. <script src="immutable.min.js"></script>
  74. <script>
  75. var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
  76. var map2 = map1.set('b', 50);
  77. map1.get('b'); // 2
  78. map2.get('b'); // 50
  79. </script>
  80. ```
  81. Or use an AMD-style loader (such as [RequireJS](https://requirejs.org/)):
  82. ```js
  83. require(['./immutable.min.js'], function (Immutable) {
  84. var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
  85. var map2 = map1.set('b', 50);
  86. map1.get('b'); // 2
  87. map2.get('b'); // 50
  88. });
  89. ```
  90. ### Flow & TypeScript
  91. Use these Immutable collections and sequences as you would use native
  92. collections in your [Flowtype](https://flowtype.org/) or [TypeScript](https://typescriptlang.org) programs while still taking
  93. advantage of type generics, error detection, and auto-complete in your IDE.
  94. Installing `immutable` via npm brings with it type definitions for Flow (v0.55.0 or higher)
  95. and TypeScript (v4.5 or higher), so you shouldn't need to do anything at all!
  96. #### Using TypeScript with Immutable.js v4+
  97. Immutable.js type definitions embrace ES2015. While Immutable.js itself supports
  98. legacy browsers and environments, its type definitions require TypeScript's 2015
  99. lib. Include either `"target": "es2015"` or `"lib": "es2015"` in your
  100. `tsconfig.json`, or provide `--target es2015` or `--lib es2015` to the
  101. `tsc` command.
  102. ```js
  103. import { Map } from 'immutable';
  104. const map1 = Map({ a: 1, b: 2, c: 3 });
  105. const map2 = map1.set('b', 50);
  106. map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50
  107. ```
  108. #### Using TypeScript with Immutable.js v3 and earlier:
  109. Previous versions of Immutable.js include a reference file which you can include
  110. via relative path to the type definitions at the top of your file.
  111. ```js
  112. ///<reference path='./node_modules/immutable/dist/immutable.d.ts'/>
  113. import { Map } from 'immutable';
  114. var map1: Map<string, number>;
  115. map1 = Map({ a: 1, b: 2, c: 3 });
  116. var map2 = map1.set('b', 50);
  117. map1.get('b'); // 2
  118. map2.get('b'); // 50
  119. ```
  120. ## The case for Immutability
  121. Much of what makes application development difficult is tracking mutation and
  122. maintaining state. Developing with immutable data encourages you to think
  123. differently about how data flows through your application.
  124. Subscribing to data events throughout your application creates a huge overhead of
  125. book-keeping which can hurt performance, sometimes dramatically, and creates
  126. opportunities for areas of your application to get out of sync with each other
  127. due to easy to make programmer error. Since immutable data never changes,
  128. subscribing to changes throughout the model is a dead-end and new data can only
  129. ever be passed from above.
  130. This model of data flow aligns well with the architecture of [React][]
  131. and especially well with an application designed using the ideas of [Flux][].
  132. When data is passed from above rather than being subscribed to, and you're only
  133. interested in doing work when something has changed, you can use equality.
  134. Immutable collections should be treated as _values_ rather than _objects_. While
  135. objects represent some thing which could change over time, a value represents
  136. the state of that thing at a particular instance of time. This principle is most
  137. important to understanding the appropriate use of immutable data. In order to
  138. treat Immutable.js collections as values, it's important to use the
  139. `Immutable.is()` function or `.equals()` method to determine _value equality_
  140. instead of the `===` operator which determines object _reference identity_.
  141. ```js
  142. import { Map } from 'immutable';
  143. const map1 = Map({ a: 1, b: 2, c: 3 });
  144. const map2 = Map({ a: 1, b: 2, c: 3 });
  145. map1.equals(map2); // true
  146. map1 === map2; // false
  147. ```
  148. Note: As a performance optimization Immutable.js attempts to return the existing
  149. collection when an operation would result in an identical collection, allowing
  150. for using `===` reference equality to determine if something definitely has not
  151. changed. This can be extremely useful when used within a memoization function
  152. which would prefer to re-run the function if a deeper equality check could
  153. potentially be more costly. The `===` equality check is also used internally by
  154. `Immutable.is` and `.equals()` as a performance optimization.
  155. ```js
  156. import { Map } from 'immutable';
  157. const map1 = Map({ a: 1, b: 2, c: 3 });
  158. const map2 = map1.set('b', 2); // Set to same value
  159. map1 === map2; // true
  160. ```
  161. If an object is immutable, it can be "copied" simply by making another reference
  162. to it instead of copying the entire object. Because a reference is much smaller
  163. than the object itself, this results in memory savings and a potential boost in
  164. execution speed for programs which rely on copies (such as an undo-stack).
  165. ```js
  166. import { Map } from 'immutable';
  167. const map = Map({ a: 1, b: 2, c: 3 });
  168. const mapCopy = map; // Look, "copies" are free!
  169. ```
  170. [React]: https://reactjs.org/
  171. [Flux]: https://facebook.github.io/flux/docs/in-depth-overview/
  172. ## JavaScript-first API
  173. While Immutable.js is inspired by Clojure, Scala, Haskell and other functional
  174. programming environments, it's designed to bring these powerful concepts to
  175. JavaScript, and therefore has an Object-Oriented API that closely mirrors that
  176. of [ES2015][] [Array][], [Map][], and [Set][].
  177. [es2015]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla
  178. [array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
  179. [map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
  180. [set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
  181. The difference for the immutable collections is that methods which would mutate
  182. the collection, like `push`, `set`, `unshift` or `splice`, instead return a new
  183. immutable collection. Methods which return new arrays, like `slice` or `concat`,
  184. instead return new immutable collections.
  185. ```js
  186. import { List } from 'immutable';
  187. const list1 = List([1, 2]);
  188. const list2 = list1.push(3, 4, 5);
  189. const list3 = list2.unshift(0);
  190. const list4 = list1.concat(list2, list3);
  191. assert.equal(list1.size, 2);
  192. assert.equal(list2.size, 5);
  193. assert.equal(list3.size, 6);
  194. assert.equal(list4.size, 13);
  195. assert.equal(list4.get(0), 1);
  196. ```
  197. Almost all of the methods on [Array][] will be found in similar form on
  198. `Immutable.List`, those of [Map][] found on `Immutable.Map`, and those of [Set][]
  199. found on `Immutable.Set`, including collection operations like `forEach()`
  200. and `map()`.
  201. ```js
  202. import { Map } from 'immutable';
  203. const alpha = Map({ a: 1, b: 2, c: 3, d: 4 });
  204. alpha.map((v, k) => k.toUpperCase()).join();
  205. // 'A,B,C,D'
  206. ```
  207. ### Convert from raw JavaScript objects and arrays.
  208. Designed to inter-operate with your existing JavaScript, Immutable.js
  209. accepts plain JavaScript Arrays and Objects anywhere a method expects a
  210. `Collection`.
  211. ```js
  212. import { Map, List } from 'immutable';
  213. const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
  214. const map2 = Map({ c: 10, a: 20, t: 30 });
  215. const obj = { d: 100, o: 200, g: 300 };
  216. const map3 = map1.merge(map2, obj);
  217. // Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
  218. const list1 = List([1, 2, 3]);
  219. const list2 = List([4, 5, 6]);
  220. const array = [7, 8, 9];
  221. const list3 = list1.concat(list2, array);
  222. // List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
  223. ```
  224. This is possible because Immutable.js can treat any JavaScript Array or Object
  225. as a Collection. You can take advantage of this in order to get sophisticated
  226. collection methods on JavaScript Objects, which otherwise have a very sparse
  227. native API. Because Seq evaluates lazily and does not cache intermediate
  228. results, these operations can be extremely efficient.
  229. ```js
  230. import { Seq } from 'immutable';
  231. const myObject = { a: 1, b: 2, c: 3 };
  232. Seq(myObject)
  233. .map((x) => x * x)
  234. .toObject();
  235. // { a: 1, b: 4, c: 9 }
  236. ```
  237. Keep in mind, when using JS objects to construct Immutable Maps, that
  238. JavaScript Object properties are always strings, even if written in a quote-less
  239. shorthand, while Immutable Maps accept keys of any type.
  240. ```js
  241. import { fromJS } from 'immutable';
  242. const obj = { 1: 'one' };
  243. console.log(Object.keys(obj)); // [ "1" ]
  244. console.log(obj['1'], obj[1]); // "one", "one"
  245. const map = fromJS(obj);
  246. console.log(map.get('1'), map.get(1)); // "one", undefined
  247. ```
  248. Property access for JavaScript Objects first converts the key to a string, but
  249. since Immutable Map keys can be of any type the argument to `get()` is
  250. not altered.
  251. ### Converts back to raw JavaScript objects.
  252. All Immutable.js Collections can be converted to plain JavaScript Arrays and
  253. Objects shallowly with `toArray()` and `toObject()` or deeply with `toJS()`.
  254. All Immutable Collections also implement `toJSON()` allowing them to be passed
  255. to `JSON.stringify` directly. They also respect the custom `toJSON()` methods of
  256. nested objects.
  257. ```js
  258. import { Map, List } from 'immutable';
  259. const deep = Map({ a: 1, b: 2, c: List([3, 4, 5]) });
  260. console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
  261. console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
  262. console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
  263. JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'
  264. ```
  265. ### Embraces ES2015
  266. Immutable.js supports all JavaScript environments, including legacy
  267. browsers (even IE11). However it also takes advantage of features added to
  268. JavaScript in [ES2015][], the latest standard version of JavaScript, including
  269. [Iterators][], [Arrow Functions][], [Classes][], and [Modules][]. It's inspired
  270. by the native [Map][] and [Set][] collections added to ES2015.
  271. All examples in the Documentation are presented in ES2015. To run in all
  272. browsers, they need to be translated to ES5.
  273. ```js
  274. // ES2015
  275. const mapped = foo.map((x) => x * x);
  276. // ES5
  277. var mapped = foo.map(function (x) {
  278. return x * x;
  279. });
  280. ```
  281. All Immutable.js collections are [Iterable][iterators], which allows them to be
  282. used anywhere an Iterable is expected, such as when spreading into an Array.
  283. ```js
  284. import { List } from 'immutable';
  285. const aList = List([1, 2, 3]);
  286. const anArray = [0, ...aList, 4, 5]; // [ 0, 1, 2, 3, 4, 5 ]
  287. ```
  288. Note: A Collection is always iterated in the same order, however that order may
  289. not always be well defined, as is the case for the `Map` and `Set`.
  290. [Iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol
  291. [Arrow Functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
  292. [Classes]: https://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes
  293. [Modules]: https://www.2ality.com/2014/09/es6-modules-final.html
  294. ## Nested Structures
  295. The collections in Immutable.js are intended to be nested, allowing for deep
  296. trees of data, similar to JSON.
  297. ```js
  298. import { fromJS } from 'immutable';
  299. const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
  300. // Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }
  301. ```
  302. A few power-tools allow for reading and operating on nested data. The
  303. most useful are `mergeDeep`, `getIn`, `setIn`, and `updateIn`, found on `List`,
  304. `Map` and `OrderedMap`.
  305. ```js
  306. import { fromJS } from 'immutable';
  307. const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
  308. const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
  309. // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
  310. console.log(nested2.getIn(['a', 'b', 'd'])); // 6
  311. const nested3 = nested2.updateIn(['a', 'b', 'd'], (value) => value + 1);
  312. console.log(nested3);
  313. // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
  314. const nested4 = nested3.updateIn(['a', 'b', 'c'], (list) => list.push(6));
  315. // Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
  316. ```
  317. ## Equality treats Collections as Values
  318. Immutable.js collections are treated as pure data _values_. Two immutable
  319. collections are considered _value equal_ (via `.equals()` or `is()`) if they
  320. represent the same collection of values. This differs from JavaScript's typical
  321. _reference equal_ (via `===` or `==`) for Objects and Arrays which only
  322. determines if two variables represent references to the same object instance.
  323. Consider the example below where two identical `Map` instances are not
  324. _reference equal_ but are _value equal_.
  325. ```js
  326. // First consider:
  327. const obj1 = { a: 1, b: 2, c: 3 };
  328. const obj2 = { a: 1, b: 2, c: 3 };
  329. obj1 !== obj2; // two different instances are always not equal with ===
  330. import { Map, is } from 'immutable';
  331. const map1 = Map({ a: 1, b: 2, c: 3 });
  332. const map2 = Map({ a: 1, b: 2, c: 3 });
  333. map1 !== map2; // two different instances are not reference-equal
  334. map1.equals(map2); // but are value-equal if they have the same values
  335. is(map1, map2); // alternatively can use the is() function
  336. ```
  337. Value equality allows Immutable.js collections to be used as keys in Maps or
  338. values in Sets, and retrieved with different but equivalent collections:
  339. ```js
  340. import { Map, Set } from 'immutable';
  341. const map1 = Map({ a: 1, b: 2, c: 3 });
  342. const map2 = Map({ a: 1, b: 2, c: 3 });
  343. const set = Set().add(map1);
  344. set.has(map2); // true because these are value-equal
  345. ```
  346. Note: `is()` uses the same measure of equality as [Object.is][] for scalar
  347. strings and numbers, but uses value equality for Immutable collections,
  348. determining if both are immutable and all keys and values are equal
  349. using the same measure of equality.
  350. [object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
  351. #### Performance tradeoffs
  352. While value equality is useful in many circumstances, it has different
  353. performance characteristics than reference equality. Understanding these
  354. tradeoffs may help you decide which to use in each case, especially when used
  355. to memoize some operation.
  356. When comparing two collections, value equality may require considering every
  357. item in each collection, on an `O(N)` time complexity. For large collections of
  358. values, this could become a costly operation. Though if the two are not equal
  359. and hardly similar, the inequality is determined very quickly. In contrast, when
  360. comparing two collections with reference equality, only the initial references
  361. to memory need to be compared which is not based on the size of the collections,
  362. which has an `O(1)` time complexity. Checking reference equality is always very
  363. fast, however just because two collections are not reference-equal does not rule
  364. out the possibility that they may be value-equal.
  365. #### Return self on no-op optimization
  366. When possible, Immutable.js avoids creating new objects for updates where no
  367. change in _value_ occurred, to allow for efficient _reference equality_ checking
  368. to quickly determine if no change occurred.
  369. ```js
  370. import { Map } from 'immutable';
  371. const originalMap = Map({ a: 1, b: 2, c: 3 });
  372. const updatedMap = originalMap.set('b', 2);
  373. updatedMap === originalMap; // No-op .set() returned the original reference.
  374. ```
  375. However updates which do result in a change will return a new reference. Each
  376. of these operations occur independently, so two similar updates will not return
  377. the same reference:
  378. ```js
  379. import { Map } from 'immutable';
  380. const originalMap = Map({ a: 1, b: 2, c: 3 });
  381. const updatedMap = originalMap.set('b', 1000);
  382. // New instance, leaving the original immutable.
  383. updatedMap !== originalMap;
  384. const anotherUpdatedMap = originalMap.set('b', 1000);
  385. // Despite both the results of the same operation, each created a new reference.
  386. anotherUpdatedMap !== updatedMap;
  387. // However the two are value equal.
  388. anotherUpdatedMap.equals(updatedMap);
  389. ```
  390. ## Batching Mutations
  391. > If a tree falls in the woods, does it make a sound?
  392. >
  393. > If a pure function mutates some local data in order to produce an immutable
  394. > return value, is that ok?
  395. >
  396. > — Rich Hickey, Clojure
  397. Applying a mutation to create a new immutable object results in some overhead,
  398. which can add up to a minor performance penalty. If you need to apply a series
  399. of mutations locally before returning, Immutable.js gives you the ability to
  400. create a temporary mutable (transient) copy of a collection and apply a batch of
  401. mutations in a performant manner by using `withMutations`. In fact, this is
  402. exactly how Immutable.js applies complex mutations itself.
  403. As an example, building `list2` results in the creation of 1, not 3, new
  404. immutable Lists.
  405. ```js
  406. import { List } from 'immutable';
  407. const list1 = List([1, 2, 3]);
  408. const list2 = list1.withMutations(function (list) {
  409. list.push(4).push(5).push(6);
  410. });
  411. assert.equal(list1.size, 3);
  412. assert.equal(list2.size, 6);
  413. ```
  414. Note: Immutable.js also provides `asMutable` and `asImmutable`, but only
  415. encourages their use when `withMutations` will not suffice. Use caution to not
  416. return a mutable copy, which could result in undesired behavior.
  417. _Important!_: Only a select few methods can be used in `withMutations` including
  418. `set`, `push` and `pop`. These methods can be applied directly against a
  419. persistent data-structure where other methods like `map`, `filter`, `sort`,
  420. and `splice` will always return new immutable data-structures and never mutate
  421. a mutable collection.
  422. ## Lazy Seq
  423. `Seq` describes a lazy operation, allowing them to efficiently chain
  424. use of all the higher-order collection methods (such as `map` and `filter`)
  425. by not creating intermediate collections.
  426. **Seq is immutable** — Once a Seq is created, it cannot be
  427. changed, appended to, rearranged or otherwise modified. Instead, any mutative
  428. method called on a `Seq` will return a new `Seq`.
  429. **Seq is lazy** — `Seq` does as little work as necessary to respond to any
  430. method call. Values are often created during iteration, including implicit
  431. iteration when reducing or converting to a concrete data structure such as
  432. a `List` or JavaScript `Array`.
  433. For example, the following performs no work, because the resulting
  434. `Seq`'s values are never iterated:
  435. ```js
  436. import { Seq } from 'immutable';
  437. const oddSquares = Seq([1, 2, 3, 4, 5, 6, 7, 8])
  438. .filter((x) => x % 2 !== 0)
  439. .map((x) => x * x);
  440. ```
  441. Once the `Seq` is used, it performs only the work necessary. In this
  442. example, no intermediate arrays are ever created, filter is called three
  443. times, and map is only called once:
  444. ```js
  445. oddSquares.get(1); // 9
  446. ```
  447. Any collection can be converted to a lazy Seq with `Seq()`.
  448. ```js
  449. import { Map, Seq } from 'immutable';
  450. const map = Map({ a: 1, b: 2, c: 3 });
  451. const lazySeq = Seq(map);
  452. ```
  453. `Seq` allows for the efficient chaining of operations, allowing for the
  454. expression of logic that can otherwise be very tedious:
  455. ```js
  456. lazySeq
  457. .flip()
  458. .map((key) => key.toUpperCase())
  459. .flip();
  460. // Seq { A: 1, B: 2, C: 3 }
  461. ```
  462. As well as expressing logic that would otherwise seem memory or time
  463. limited, for example `Range` is a special kind of Lazy sequence.
  464. ```js
  465. import { Range } from 'immutable';
  466. Range(1, Infinity)
  467. .skip(1000)
  468. .map((n) => -n)
  469. .filter((n) => n % 2 === 0)
  470. .take(2)
  471. .reduce((r, n) => r * n, 1);
  472. // 1006008
  473. ```
  474. ## Comparison of filter(), groupBy(), and partition()
  475. The `filter()`, `groupBy()`, and `partition()` methods are similar in that they
  476. all divide a collection into parts based on applying a function to each element.
  477. All three call the predicate or grouping function once for each item in the
  478. input collection. All three return zero or more collections of the same type as
  479. their input. The returned collections are always distinct from the input
  480. (according to `===`), even if the contents are identical.
  481. Of these methods, `filter()` is the only one that is lazy and the only one which
  482. discards items from the input collection. It is the simplest to use, and the
  483. fact that it returns exactly one collection makes it easy to combine with other
  484. methods to form a pipeline of operations.
  485. The `partition()` method is similar to an eager version of `filter()`, but it
  486. returns two collections; the first contains the items that would have been
  487. discarded by `filter()`, and the second contains the items that would have been
  488. kept. It always returns an array of exactly two collections, which can make it
  489. easier to use than `groupBy()`. Compared to making two separate calls to
  490. `filter()`, `partition()` makes half as many calls it the predicate passed to
  491. it.
  492. The `groupBy()` method is a more generalized version of `partition()` that can
  493. group by an arbitrary function rather than just a predicate. It returns a map
  494. with zero or more entries, where the keys are the values returned by the
  495. grouping function, and the values are nonempty collections of the corresponding
  496. arguments. Although `groupBy()` is more powerful than `partition()`, it can be
  497. harder to use because it is not always possible predict in advance how many
  498. entries the returned map will have and what their keys will be.
  499. | Summary | `filter` | `partition` | `groupBy` |
  500. | :---------------------------- | :------- | :---------- | :------------- |
  501. | ease of use | easiest | moderate | hardest |
  502. | generality | least | moderate | most |
  503. | laziness | lazy | eager | eager |
  504. | # of returned sub-collections | 1 | 2 | 0 or more |
  505. | sub-collections may be empty | yes | yes | no |
  506. | can discard items | yes | no | no |
  507. | wrapping container | none | array | Map/OrderedMap |
  508. ## Additional Tools and Resources
  509. - [Atom-store](https://github.com/jameshopkins/atom-store/)
  510. - A Clojure-inspired atom implementation in Javascript with configurability
  511. for external persistance.
  512. - [Chai Immutable](https://github.com/astorije/chai-immutable)
  513. - If you are using the [Chai Assertion Library](https://chaijs.com/), this
  514. provides a set of assertions to use against Immutable.js collections.
  515. - [Fantasy-land](https://github.com/fantasyland/fantasy-land)
  516. - Specification for interoperability of common algebraic structures in JavaScript.
  517. - [Immutagen](https://github.com/pelotom/immutagen)
  518. - A library for simulating immutable generators in JavaScript.
  519. - [Immutable-cursor](https://github.com/redbadger/immutable-cursor)
  520. - Immutable cursors incorporating the Immutable.js interface over
  521. Clojure-inspired atom.
  522. - [Immutable-ext](https://github.com/DrBoolean/immutable-ext)
  523. - Fantasyland extensions for immutablejs
  524. - [Immutable-js-tools](https://github.com/madeinfree/immutable-js-tools)
  525. - Util tools for immutable.js
  526. - [Immutable-Redux](https://github.com/gajus/redux-immutable)
  527. - redux-immutable is used to create an equivalent function of Redux
  528. combineReducers that works with Immutable.js state.
  529. - [Immutable-Treeutils](https://github.com/lukasbuenger/immutable-treeutils)
  530. - Functional tree traversal helpers for ImmutableJS data structures.
  531. - [Irecord](https://github.com/ericelliott/irecord)
  532. - An immutable store that exposes an RxJS observable. Great for React.
  533. - [Mudash](https://github.com/brianneisler/mudash)
  534. - Lodash wrapper providing Immutable.JS support.
  535. - [React-Immutable-PropTypes](https://github.com/HurricaneJames/react-immutable-proptypes)
  536. - PropType validators that work with Immutable.js.
  537. - [Redux-Immutablejs](https://github.com/indexiatech/redux-immutablejs)
  538. - Redux Immutable facilities.
  539. - [Rxstate](https://github.com/yamalight/rxstate)
  540. - Simple opinionated state management library based on RxJS and Immutable.js.
  541. - [Transit-Immutable-js](https://github.com/glenjamin/transit-immutable-js)
  542. - Transit serialisation for Immutable.js.
  543. - See also: [Transit-js](https://github.com/cognitect/transit-js)
  544. Have an additional tool designed to work with Immutable.js?
  545. Submit a PR to add it to this list in alphabetical order.
  546. ## Contributing
  547. Use [Github issues](https://github.com/immutable-js/immutable-js/issues) for requests.
  548. We actively welcome pull requests, learn how to [contribute](https://github.com/immutable-js/immutable-js/blob/main/.github/CONTRIBUTING.md).
  549. Immutable.js is maintained within the [Contributor Covenant's Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/).
  550. ### Changelog
  551. Changes are tracked as [Github releases](https://github.com/immutable-js/immutable-js/releases).
  552. ### License
  553. Immutable.js is [MIT-licensed](./LICENSE).
  554. ### Thanks
  555. [Phil Bagwell](https://www.youtube.com/watch?v=K2NYwP90bNs), for his inspiration
  556. and research in persistent data structures.
  557. [Hugh Jackson](https://github.com/hughfdjackson/), for providing the npm package
  558. name. If you're looking for his unsupported package, see [this repository](https://github.com/hughfdjackson/immutable).