immutable 4.0.0-rc.6 → 4.0.0

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