Spaces:
Build error
Build error
| # Immutable collections for JavaScript | |
| [](https://github.com/immutable-js/immutable-js/actions/workflows/ci.yml?query=branch%3Amain) [Chat on slack](https://immutable-js.slack.com) | |
| [Read the docs](https://immutable-js.com) and eat your vegetables. | |
| Docs are automatically generated from [README.md][] and [immutable.d.ts][]. | |
| Please contribute! Also, don't miss the [wiki][] which contains articles on | |
| additional specific topics. Can't find something? Open an [issue][]. | |
| **Table of contents:** | |
| - [Introduction](#introduction) | |
| - [Getting started](#getting-started) | |
| - [The case for Immutability](#the-case-for-immutability) | |
| - [JavaScript-first API](#javascript-first-api) | |
| - [Nested Structures](#nested-structures) | |
| - [Equality treats Collections as Values](#equality-treats-collections-as-values) | |
| - [Batching Mutations](#batching-mutations) | |
| - [Lazy Seq](#lazy-seq) | |
| - [Additional Tools and Resources](#additional-tools-and-resources) | |
| - [Contributing](#contributing) | |
| ## Introduction | |
| [Immutable][] data cannot be changed once created, leading to much simpler | |
| application development, no defensive copying, and enabling advanced memoization | |
| and change detection techniques with simple logic. [Persistent][] data presents | |
| a mutative API which does not update the data in-place, but instead always | |
| yields new updated data. | |
| Immutable.js provides many Persistent Immutable data structures including: | |
| `List`, `Stack`, `Map`, `OrderedMap`, `Set`, `OrderedSet` and `Record`. | |
| These data structures are highly efficient on modern JavaScript VMs by using | |
| structural sharing via [hash maps tries][] and [vector tries][] as popularized | |
| by Clojure and Scala, minimizing the need to copy or cache data. | |
| Immutable.js also provides a lazy `Seq`, allowing efficient | |
| chaining of collection methods like `map` and `filter` without creating | |
| intermediate representations. Create some `Seq` with `Range` and `Repeat`. | |
| Want to hear more? Watch the presentation about Immutable.js: | |
| [](https://youtu.be/I7IdS-PbEgI) | |
| [README.md]: https://github.com/immutable-js/immutable-js/blob/main/README.md | |
| [immutable.d.ts]: https://github.com/immutable-js/immutable-js/blob/main/type-definitions/immutable.d.ts | |
| [wiki]: https://github.com/immutable-js/immutable-js/wiki | |
| [issue]: https://github.com/immutable-js/immutable-js/issues | |
| [Persistent]: https://en.wikipedia.org/wiki/Persistent_data_structure | |
| [Immutable]: https://en.wikipedia.org/wiki/Immutable_object | |
| [hash maps tries]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie | |
| [vector tries]: https://hypirion.com/musings/understanding-persistent-vector-pt-1 | |
| ## Getting started | |
| Install `immutable` using npm. | |
| ```shell | |
| npm install immutable | |
| ``` | |
| Or install using yarn. | |
| ```shell | |
| yarn add immutable | |
| ``` | |
| Then require it into any module. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3 }); | |
| const map2 = map1.set('b', 50); | |
| map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50 | |
| ``` | |
| ### Browser | |
| Immutable.js has no dependencies, which makes it predictable to include in a Browser. | |
| It's highly recommended to use a module bundler like [webpack](https://webpack.github.io/), | |
| [rollup](https://rollupjs.org/), or | |
| [browserify](https://browserify.org/). The `immutable` npm module works | |
| without any additional consideration. All examples throughout the documentation | |
| will assume use of this kind of tool. | |
| Alternatively, Immutable.js may be directly included as a script tag. Download | |
| or link to a CDN such as [CDNJS](https://cdnjs.com/libraries/immutable) | |
| or [jsDelivr](https://www.jsdelivr.com/package/npm/immutable). | |
| Use a script tag to directly add `Immutable` to the global scope: | |
| ```html | |
| <script src="immutable.min.js"></script> | |
| <script> | |
| var map1 = Immutable.Map({ a: 1, b: 2, c: 3 }); | |
| var map2 = map1.set('b', 50); | |
| map1.get('b'); // 2 | |
| map2.get('b'); // 50 | |
| </script> | |
| ``` | |
| Or use an AMD-style loader (such as [RequireJS](https://requirejs.org/)): | |
| ```js | |
| require(['./immutable.min.js'], function (Immutable) { | |
| var map1 = Immutable.Map({ a: 1, b: 2, c: 3 }); | |
| var map2 = map1.set('b', 50); | |
| map1.get('b'); // 2 | |
| map2.get('b'); // 50 | |
| }); | |
| ``` | |
| ### Flow & TypeScript | |
| Use these Immutable collections and sequences as you would use native | |
| collections in your [Flowtype](https://flowtype.org/) or [TypeScript](https://typescriptlang.org) programs while still taking | |
| advantage of type generics, error detection, and auto-complete in your IDE. | |
| Installing `immutable` via npm brings with it type definitions for Flow (v0.55.0 or higher) | |
| and TypeScript (v2.1.0 or higher), so you shouldn't need to do anything at all! | |
| #### Using TypeScript with Immutable.js v4 | |
| Immutable.js type definitions embrace ES2015. While Immutable.js itself supports | |
| legacy browsers and environments, its type definitions require TypeScript's 2015 | |
| lib. Include either `"target": "es2015"` or `"lib": "es2015"` in your | |
| `tsconfig.json`, or provide `--target es2015` or `--lib es2015` to the | |
| `tsc` command. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3 }); | |
| const map2 = map1.set('b', 50); | |
| map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50 | |
| ``` | |
| #### Using TypeScript with Immutable.js v3 and earlier: | |
| Previous versions of Immutable.js include a reference file which you can include | |
| via relative path to the type definitions at the top of your file. | |
| ```js | |
| ///<reference path='./node_modules/immutable/dist/immutable.d.ts'/> | |
| import Immutable from 'immutable'; | |
| var map1: Immutable.Map<string, number>; | |
| map1 = Immutable.Map({ a: 1, b: 2, c: 3 }); | |
| var map2 = map1.set('b', 50); | |
| map1.get('b'); // 2 | |
| map2.get('b'); // 50 | |
| ``` | |
| ## The case for Immutability | |
| Much of what makes application development difficult is tracking mutation and | |
| maintaining state. Developing with immutable data encourages you to think | |
| differently about how data flows through your application. | |
| Subscribing to data events throughout your application creates a huge overhead of | |
| book-keeping which can hurt performance, sometimes dramatically, and creates | |
| opportunities for areas of your application to get out of sync with each other | |
| due to easy to make programmer error. Since immutable data never changes, | |
| subscribing to changes throughout the model is a dead-end and new data can only | |
| ever be passed from above. | |
| This model of data flow aligns well with the architecture of [React][] | |
| and especially well with an application designed using the ideas of [Flux][]. | |
| When data is passed from above rather than being subscribed to, and you're only | |
| interested in doing work when something has changed, you can use equality. | |
| Immutable collections should be treated as _values_ rather than _objects_. While | |
| objects represent some thing which could change over time, a value represents | |
| the state of that thing at a particular instance of time. This principle is most | |
| important to understanding the appropriate use of immutable data. In order to | |
| treat Immutable.js collections as values, it's important to use the | |
| `Immutable.is()` function or `.equals()` method to determine _value equality_ | |
| instead of the `===` operator which determines object _reference identity_. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3 }); | |
| const map2 = Map({ a: 1, b: 2, c: 3 }); | |
| map1.equals(map2); // true | |
| map1 === map2; // false | |
| ``` | |
| Note: As a performance optimization Immutable.js attempts to return the existing | |
| collection when an operation would result in an identical collection, allowing | |
| for using `===` reference equality to determine if something definitely has not | |
| changed. This can be extremely useful when used within a memoization function | |
| which would prefer to re-run the function if a deeper equality check could | |
| potentially be more costly. The `===` equality check is also used internally by | |
| `Immutable.is` and `.equals()` as a performance optimization. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3 }); | |
| const map2 = map1.set('b', 2); // Set to same value | |
| map1 === map2; // true | |
| ``` | |
| If an object is immutable, it can be "copied" simply by making another reference | |
| to it instead of copying the entire object. Because a reference is much smaller | |
| than the object itself, this results in memory savings and a potential boost in | |
| execution speed for programs which rely on copies (such as an undo-stack). | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const map = Map({ a: 1, b: 2, c: 3 }); | |
| const mapCopy = map; // Look, "copies" are free! | |
| ``` | |
| [React]: https://reactjs.org/ | |
| [Flux]: https://facebook.github.io/flux/docs/in-depth-overview/ | |
| ## JavaScript-first API | |
| While Immutable.js is inspired by Clojure, Scala, Haskell and other functional | |
| programming environments, it's designed to bring these powerful concepts to | |
| JavaScript, and therefore has an Object-Oriented API that closely mirrors that | |
| of [ES2015][] [Array][], [Map][], and [Set][]. | |
| [es2015]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla | |
| [array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array | |
| [map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map | |
| [set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set | |
| The difference for the immutable collections is that methods which would mutate | |
| the collection, like `push`, `set`, `unshift` or `splice`, instead return a new | |
| immutable collection. Methods which return new arrays, like `slice` or `concat`, | |
| instead return new immutable collections. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { List } = require('immutable'); | |
| const list1 = List([1, 2]); | |
| const list2 = list1.push(3, 4, 5); | |
| const list3 = list2.unshift(0); | |
| const list4 = list1.concat(list2, list3); | |
| assert.equal(list1.size, 2); | |
| assert.equal(list2.size, 5); | |
| assert.equal(list3.size, 6); | |
| assert.equal(list4.size, 13); | |
| assert.equal(list4.get(0), 1); | |
| ``` | |
| Almost all of the methods on [Array][] will be found in similar form on | |
| `Immutable.List`, those of [Map][] found on `Immutable.Map`, and those of [Set][] | |
| found on `Immutable.Set`, including collection operations like `forEach()` | |
| and `map()`. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const alpha = Map({ a: 1, b: 2, c: 3, d: 4 }); | |
| alpha.map((v, k) => k.toUpperCase()).join(); | |
| // 'A,B,C,D' | |
| ``` | |
| ### Convert from raw JavaScript objects and arrays. | |
| Designed to inter-operate with your existing JavaScript, Immutable.js | |
| accepts plain JavaScript Arrays and Objects anywhere a method expects a | |
| `Collection`. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map, List } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3, d: 4 }); | |
| const map2 = Map({ c: 10, a: 20, t: 30 }); | |
| const obj = { d: 100, o: 200, g: 300 }; | |
| const map3 = map1.merge(map2, obj); | |
| // Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 } | |
| const list1 = List([1, 2, 3]); | |
| const list2 = List([4, 5, 6]); | |
| const array = [7, 8, 9]; | |
| const list3 = list1.concat(list2, array); | |
| // List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] | |
| ``` | |
| This is possible because Immutable.js can treat any JavaScript Array or Object | |
| as a Collection. You can take advantage of this in order to get sophisticated | |
| collection methods on JavaScript Objects, which otherwise have a very sparse | |
| native API. Because Seq evaluates lazily and does not cache intermediate | |
| results, these operations can be extremely efficient. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Seq } = require('immutable'); | |
| const myObject = { a: 1, b: 2, c: 3 }; | |
| Seq(myObject) | |
| .map(x => x * x) | |
| .toObject(); | |
| // { a: 1, b: 4, c: 9 } | |
| ``` | |
| Keep in mind, when using JS objects to construct Immutable Maps, that | |
| JavaScript Object properties are always strings, even if written in a quote-less | |
| shorthand, while Immutable Maps accept keys of any type. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { fromJS } = require('immutable'); | |
| const obj = { 1: 'one' }; | |
| console.log(Object.keys(obj)); // [ "1" ] | |
| console.log(obj['1'], obj[1]); // "one", "one" | |
| const map = fromJS(obj); | |
| console.log(map.get('1'), map.get(1)); // "one", undefined | |
| ``` | |
| Property access for JavaScript Objects first converts the key to a string, but | |
| since Immutable Map keys can be of any type the argument to `get()` is | |
| not altered. | |
| ### Converts back to raw JavaScript objects. | |
| All Immutable.js Collections can be converted to plain JavaScript Arrays and | |
| Objects shallowly with `toArray()` and `toObject()` or deeply with `toJS()`. | |
| All Immutable Collections also implement `toJSON()` allowing them to be passed | |
| to `JSON.stringify` directly. They also respect the custom `toJSON()` methods of | |
| nested objects. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map, List } = require('immutable'); | |
| const deep = Map({ a: 1, b: 2, c: List([3, 4, 5]) }); | |
| console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] } | |
| console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ] | |
| console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] } | |
| JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}' | |
| ``` | |
| ### Embraces ES2015 | |
| Immutable.js supports all JavaScript environments, including legacy | |
| browsers (even IE11). However it also takes advantage of features added to | |
| JavaScript in [ES2015][], the latest standard version of JavaScript, including | |
| [Iterators][], [Arrow Functions][], [Classes][], and [Modules][]. It's inspired | |
| by the native [Map][] and [Set][] collections added to ES2015. | |
| All examples in the Documentation are presented in ES2015. To run in all | |
| browsers, they need to be translated to ES5. | |
| ```js | |
| // ES2015 | |
| const mapped = foo.map(x => x * x); | |
| // ES5 | |
| var mapped = foo.map(function (x) { | |
| return x * x; | |
| }); | |
| ``` | |
| All Immutable.js collections are [Iterable][iterators], which allows them to be | |
| used anywhere an Iterable is expected, such as when spreading into an Array. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { List } = require('immutable'); | |
| const aList = List([1, 2, 3]); | |
| const anArray = [0, ...aList, 4, 5]; // [ 0, 1, 2, 3, 4, 5 ] | |
| ``` | |
| Note: A Collection is always iterated in the same order, however that order may | |
| not always be well defined, as is the case for the `Map` and `Set`. | |
| [Iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol | |
| [Arrow Functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions | |
| [Classes]: https://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes | |
| [Modules]: https://www.2ality.com/2014/09/es6-modules-final.html | |
| ## Nested Structures | |
| The collections in Immutable.js are intended to be nested, allowing for deep | |
| trees of data, similar to JSON. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { fromJS } = require('immutable'); | |
| const nested = fromJS({ a: { b: { c: [3, 4, 5] } } }); | |
| // Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } } | |
| ``` | |
| A few power-tools allow for reading and operating on nested data. The | |
| most useful are `mergeDeep`, `getIn`, `setIn`, and `updateIn`, found on `List`, | |
| `Map` and `OrderedMap`. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { fromJS } = require('immutable'); | |
| const nested = fromJS({ a: { b: { c: [3, 4, 5] } } }); | |
| const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } }); | |
| // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } } | |
| console.log(nested2.getIn(['a', 'b', 'd'])); // 6 | |
| const nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1); | |
| console.log(nested3); | |
| // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } } | |
| const nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6)); | |
| // Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } } | |
| ``` | |
| ## Equality treats Collections as Values | |
| Immutable.js collections are treated as pure data _values_. Two immutable | |
| collections are considered _value equal_ (via `.equals()` or `is()`) if they | |
| represent the same collection of values. This differs from JavaScript's typical | |
| _reference equal_ (via `===` or `==`) for Objects and Arrays which only | |
| determines if two variables represent references to the same object instance. | |
| Consider the example below where two identical `Map` instances are not | |
| _reference equal_ but are _value equal_. | |
| <!-- runkit:activate --> | |
| ```js | |
| // First consider: | |
| const obj1 = { a: 1, b: 2, c: 3 }; | |
| const obj2 = { a: 1, b: 2, c: 3 }; | |
| obj1 !== obj2; // two different instances are always not equal with === | |
| const { Map, is } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3 }); | |
| const map2 = Map({ a: 1, b: 2, c: 3 }); | |
| map1 !== map2; // two different instances are not reference-equal | |
| map1.equals(map2); // but are value-equal if they have the same values | |
| is(map1, map2); // alternatively can use the is() function | |
| ``` | |
| Value equality allows Immutable.js collections to be used as keys in Maps or | |
| values in Sets, and retrieved with different but equivalent collections: | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map, Set } = require('immutable'); | |
| const map1 = Map({ a: 1, b: 2, c: 3 }); | |
| const map2 = Map({ a: 1, b: 2, c: 3 }); | |
| const set = Set().add(map1); | |
| set.has(map2); // true because these are value-equal | |
| ``` | |
| Note: `is()` uses the same measure of equality as [Object.is][] for scalar | |
| strings and numbers, but uses value equality for Immutable collections, | |
| determining if both are immutable and all keys and values are equal | |
| using the same measure of equality. | |
| [object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is | |
| #### Performance tradeoffs | |
| While value equality is useful in many circumstances, it has different | |
| performance characteristics than reference equality. Understanding these | |
| tradeoffs may help you decide which to use in each case, especially when used | |
| to memoize some operation. | |
| When comparing two collections, value equality may require considering every | |
| item in each collection, on an `O(N)` time complexity. For large collections of | |
| values, this could become a costly operation. Though if the two are not equal | |
| and hardly similar, the inequality is determined very quickly. In contrast, when | |
| comparing two collections with reference equality, only the initial references | |
| to memory need to be compared which is not based on the size of the collections, | |
| which has an `O(1)` time complexity. Checking reference equality is always very | |
| fast, however just because two collections are not reference-equal does not rule | |
| out the possibility that they may be value-equal. | |
| #### Return self on no-op optimization | |
| When possible, Immutable.js avoids creating new objects for updates where no | |
| change in _value_ occurred, to allow for efficient _reference equality_ checking | |
| to quickly determine if no change occurred. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const originalMap = Map({ a: 1, b: 2, c: 3 }); | |
| const updatedMap = originalMap.set('b', 2); | |
| updatedMap === originalMap; // No-op .set() returned the original reference. | |
| ``` | |
| However updates which do result in a change will return a new reference. Each | |
| of these operations occur independently, so two similar updates will not return | |
| the same reference: | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map } = require('immutable'); | |
| const originalMap = Map({ a: 1, b: 2, c: 3 }); | |
| const updatedMap = originalMap.set('b', 1000); | |
| // New instance, leaving the original immutable. | |
| updatedMap !== originalMap; | |
| const anotherUpdatedMap = originalMap.set('b', 1000); | |
| // Despite both the results of the same operation, each created a new reference. | |
| anotherUpdatedMap !== updatedMap; | |
| // However the two are value equal. | |
| anotherUpdatedMap.equals(updatedMap); | |
| ``` | |
| ## Batching Mutations | |
| > If a tree falls in the woods, does it make a sound? | |
| > | |
| > If a pure function mutates some local data in order to produce an immutable | |
| > return value, is that ok? | |
| > | |
| > — Rich Hickey, Clojure | |
| Applying a mutation to create a new immutable object results in some overhead, | |
| which can add up to a minor performance penalty. If you need to apply a series | |
| of mutations locally before returning, Immutable.js gives you the ability to | |
| create a temporary mutable (transient) copy of a collection and apply a batch of | |
| mutations in a performant manner by using `withMutations`. In fact, this is | |
| exactly how Immutable.js applies complex mutations itself. | |
| As an example, building `list2` results in the creation of 1, not 3, new | |
| immutable Lists. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { List } = require('immutable'); | |
| const list1 = List([1, 2, 3]); | |
| const list2 = list1.withMutations(function (list) { | |
| list.push(4).push(5).push(6); | |
| }); | |
| assert.equal(list1.size, 3); | |
| assert.equal(list2.size, 6); | |
| ``` | |
| Note: Immutable.js also provides `asMutable` and `asImmutable`, but only | |
| encourages their use when `withMutations` will not suffice. Use caution to not | |
| return a mutable copy, which could result in undesired behavior. | |
| _Important!_: Only a select few methods can be used in `withMutations` including | |
| `set`, `push` and `pop`. These methods can be applied directly against a | |
| persistent data-structure where other methods like `map`, `filter`, `sort`, | |
| and `splice` will always return new immutable data-structures and never mutate | |
| a mutable collection. | |
| ## Lazy Seq | |
| `Seq` describes a lazy operation, allowing them to efficiently chain | |
| use of all the higher-order collection methods (such as `map` and `filter`) | |
| by not creating intermediate collections. | |
| **Seq is immutable** — Once a Seq is created, it cannot be | |
| changed, appended to, rearranged or otherwise modified. Instead, any mutative | |
| method called on a `Seq` will return a new `Seq`. | |
| **Seq is lazy** — `Seq` does as little work as necessary to respond to any | |
| method call. Values are often created during iteration, including implicit | |
| iteration when reducing or converting to a concrete data structure such as | |
| a `List` or JavaScript `Array`. | |
| For example, the following performs no work, because the resulting | |
| `Seq`'s values are never iterated: | |
| ```js | |
| const { Seq } = require('immutable'); | |
| const oddSquares = Seq([1, 2, 3, 4, 5, 6, 7, 8]) | |
| .filter(x => x % 2 !== 0) | |
| .map(x => x * x); | |
| ``` | |
| Once the `Seq` is used, it performs only the work necessary. In this | |
| example, no intermediate arrays are ever created, filter is called three | |
| times, and map is only called once: | |
| ```js | |
| oddSquares.get(1); // 9 | |
| ``` | |
| Any collection can be converted to a lazy Seq with `Seq()`. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Map, Seq } = require('immutable'); | |
| const map = Map({ a: 1, b: 2, c: 3 }); | |
| const lazySeq = Seq(map); | |
| ``` | |
| `Seq` allows for the efficient chaining of operations, allowing for the | |
| expression of logic that can otherwise be very tedious: | |
| ```js | |
| lazySeq | |
| .flip() | |
| .map(key => key.toUpperCase()) | |
| .flip(); | |
| // Seq { A: 1, B: 2, C: 3 } | |
| ``` | |
| As well as expressing logic that would otherwise seem memory or time | |
| limited, for example `Range` is a special kind of Lazy sequence. | |
| <!-- runkit:activate --> | |
| ```js | |
| const { Range } = require('immutable'); | |
| Range(1, Infinity) | |
| .skip(1000) | |
| .map(n => -n) | |
| .filter(n => n % 2 === 0) | |
| .take(2) | |
| .reduce((r, n) => r * n, 1); | |
| // 1006008 | |
| ``` | |
| ## Comparison of filter(), groupBy(), and partition() | |
| The `filter()`, `groupBy()`, and `partition()` methods are similar in that they | |
| all divide a collection into parts based on applying a function to each element. | |
| All three call the predicate or grouping function once for each item in the | |
| input collection. All three return zero or more collections of the same type as | |
| their input. The returned collections are always distinct from the input | |
| (according to `===`), even if the contents are identical. | |
| Of these methods, `filter()` is the only one that is lazy and the only one which | |
| discards items from the input collection. It is the simplest to use, and the | |
| fact that it returns exactly one collection makes it easy to combine with other | |
| methods to form a pipeline of operations. | |
| The `partition()` method is similar to an eager version of `filter()`, but it | |
| returns two collections; the first contains the items that would have been | |
| discarded by `filter()`, and the second contains the items that would have been | |
| kept. It always returns an array of exactly two collections, which can make it | |
| easier to use than `groupBy()`. Compared to making two separate calls to | |
| `filter()`, `partition()` makes half as many calls it the predicate passed to | |
| it. | |
| The `groupBy()` method is a more generalized version of `partition()` that can | |
| group by an arbitrary function rather than just a predicate. It returns a map | |
| with zero or more entries, where the keys are the values returned by the | |
| grouping function, and the values are nonempty collections of the corresponding | |
| arguments. Although `groupBy()` is more powerful than `partition()`, it can be | |
| harder to use because it is not always possible predict in advance how many | |
| entries the returned map will have and what their keys will be. | |
| | Summary | `filter` | `partition` | `groupBy` | | |
| |:------------------------------|:---------|:------------|:---------------| | |
| | ease of use | easiest | moderate | hardest | | |
| | generality | least | moderate | most | | |
| | laziness | lazy | eager | eager | | |
| | # of returned sub-collections | 1 | 2 | 0 or more | | |
| | sub-collections may be empty | yes | yes | no | | |
| | can discard items | yes | no | no | | |
| | wrapping container | none | array | Map/OrderedMap | | |
| ## Additional Tools and Resources | |
| - [Atom-store](https://github.com/jameshopkins/atom-store/) | |
| - A Clojure-inspired atom implementation in Javascript with configurability | |
| for external persistance. | |
| - [Chai Immutable](https://github.com/astorije/chai-immutable) | |
| - If you are using the [Chai Assertion Library](https://chaijs.com/), this | |
| provides a set of assertions to use against Immutable.js collections. | |
| - [Fantasy-land](https://github.com/fantasyland/fantasy-land) | |
| - Specification for interoperability of common algebraic structures in JavaScript. | |
| - [Immutagen](https://github.com/pelotom/immutagen) | |
| - A library for simulating immutable generators in JavaScript. | |
| - [Immutable-cursor](https://github.com/redbadger/immutable-cursor) | |
| - Immutable cursors incorporating the Immutable.js interface over | |
| Clojure-inspired atom. | |
| - [Immutable-ext](https://github.com/DrBoolean/immutable-ext) | |
| - Fantasyland extensions for immutablejs | |
| - [Immutable-js-tools](https://github.com/madeinfree/immutable-js-tools) | |
| - Util tools for immutable.js | |
| - [Immutable-Redux](https://github.com/gajus/redux-immutable) | |
| - redux-immutable is used to create an equivalent function of Redux | |
| combineReducers that works with Immutable.js state. | |
| - [Immutable-Treeutils](https://github.com/lukasbuenger/immutable-treeutils) | |
| - Functional tree traversal helpers for ImmutableJS data structures. | |
| - [Irecord](https://github.com/ericelliott/irecord) | |
| - An immutable store that exposes an RxJS observable. Great for React. | |
| - [Mudash](https://github.com/brianneisler/mudash) | |
| - Lodash wrapper providing Immutable.JS support. | |
| - [React-Immutable-PropTypes](https://github.com/HurricaneJames/react-immutable-proptypes) | |
| - PropType validators that work with Immutable.js. | |
| - [Redux-Immutablejs](https://github.com/indexiatech/redux-immutablejs) | |
| - Redux Immutable facilities. | |
| - [Rxstate](https://github.com/yamalight/rxstate) | |
| - Simple opinionated state management library based on RxJS and Immutable.js. | |
| - [Transit-Immutable-js](https://github.com/glenjamin/transit-immutable-js) | |
| - Transit serialisation for Immutable.js. | |
| - See also: [Transit-js](https://github.com/cognitect/transit-js) | |
| Have an additional tool designed to work with Immutable.js? | |
| Submit a PR to add it to this list in alphabetical order. | |
| ## Contributing | |
| Use [Github issues](https://github.com/immutable-js/immutable-js/issues) for requests. | |
| We actively welcome pull requests, learn how to [contribute](https://github.com/immutable-js/immutable-js/blob/main/.github/CONTRIBUTING.md). | |
| Immutable.js is maintained within the [Contributor Covenant's Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). | |
| ### Changelog | |
| Changes are tracked as [Github releases](https://github.com/immutable-js/immutable-js/releases). | |
| ### License | |
| Immutable.js is [MIT-licensed](./LICENSE). | |
| ### Thanks | |
| [Phil Bagwell](https://www.youtube.com/watch?v=K2NYwP90bNs), for his inspiration | |
| and research in persistent data structures. | |
| [Hugh Jackson](https://github.com/hughfdjackson/), for providing the npm package | |
| name. If you're looking for his unsupported package, see [this repository](https://github.com/hughfdjackson/immutable). | |