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