immutable 3.8.2 → 4.0.0-rc.12

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,7 @@
1
1
  Immutable collections for JavaScript
2
2
  ====================================
3
3
 
4
- [![Build Status](https://travis-ci.org/facebook/immutable-js.svg)](https://travis-ci.org/facebook/immutable-js)
4
+ [![Build Status](https://travis-ci.org/facebook/immutable-js.svg?branch=master)](https://travis-ci.org/facebook/immutable-js) [![Join the chat at https://gitter.im/immutable-js/Lobby](https://badges.gitter.im/immutable-js/Lobby.svg)](https://gitter.im/immutable-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
5
 
6
6
  [Immutable][] data cannot be changed once created, leading to much simpler
7
7
  application development, no defensive copying, and enabling advanced memoization
@@ -16,7 +16,7 @@ These data structures are highly efficient on modern JavaScript VMs by using
16
16
  structural sharing via [hash maps tries][] and [vector tries][] as popularized
17
17
  by Clojure and Scala, minimizing the need to copy or cache data.
18
18
 
19
- `Immutable` also provides a lazy `Seq`, allowing efficient
19
+ Immutable.js also provides a lazy `Seq`, allowing efficient
20
20
  chaining of collection methods like `map` and `filter` without creating
21
21
  intermediate representations. Create some `Seq` with `Range` and `Repeat`.
22
22
 
@@ -41,60 +41,86 @@ npm install immutable
41
41
 
42
42
  Then require it into any module.
43
43
 
44
- ```javascript
45
- var Immutable = require('immutable');
46
- var map1 = Immutable.Map({a:1, b:2, c:3});
47
- var map2 = map1.set('b', 50);
48
- map1.get('b'); // 2
49
- map2.get('b'); // 50
44
+ <!-- runkit:activate -->
45
+ ```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
50
50
  ```
51
51
 
52
52
  ### Browser
53
53
 
54
- To use `immutable` 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).
54
+ Immutable.js has no dependencies, which makes it predictable to include in a Browser.
55
+
56
+ It's highly recommended to use a module bundler like [webpack](https://webpack.github.io/),
57
+ [rollup](https://rollupjs.org/), or
58
+ [browserify](http://browserify.org/). The `immutable` npm module works
59
+ without any additional consideration. All examples throughout the documentation
60
+ will assume use of this kind of tool.
61
+
62
+ Alternatively, Immutable.js may be directly included as a script tag. Download
63
+ or link to a CDN such as [CDNJS](https://cdnjs.com/libraries/immutable)
64
+ or [jsDelivr](https://www.jsdelivr.com/package/npm/immutable).
57
65
 
58
- Then, add it as a script tag to your page:
66
+ Use a script tag to directly add `Immutable` to the global scope:
59
67
 
60
68
  ```html
61
69
  <script src="immutable.min.js"></script>
62
70
  <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
71
+ var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
72
+ var map2 = map1.set('b', 50);
73
+ map1.get('b'); // 2
74
+ map2.get('b'); // 50
67
75
  </script>
68
76
  ```
69
77
 
70
- Or use an AMD loader (such as [RequireJS](http://requirejs.org/)):
78
+ Or use an AMD-style loader (such as [RequireJS](http://requirejs.org/)):
71
79
 
72
- ```javascript
80
+ ```js
73
81
  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
82
+ var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
83
+ var map2 = map1.set('b', 50);
84
+ map1.get('b'); // 2
85
+ map2.get('b'); // 50
78
86
  });
79
87
  ```
80
88
 
81
- If you're using [browserify](http://browserify.org/), the `immutable` npm module
82
- also works from the browser.
83
-
84
- ### TypeScript
89
+ ### Flow & TypeScript
85
90
 
86
91
  Use these Immutable collections and sequences as you would use native
87
- collections in your [TypeScript](http://typescriptlang.org) programs while still taking
92
+ collections in your [Flowtype](https://flowtype.org/) or [TypeScript](http://typescriptlang.org) programs while still taking
88
93
  advantage of type generics, error detection, and auto-complete in your IDE.
89
94
 
90
- Just add a reference with a relative path to the type declarations at the top
91
- of your file.
95
+ Installing `immutable` via npm brings with it type definitions for Flow (v0.55.0 or higher)
96
+ and TypeScript (v2.1.0 or higher), so you shouldn't need to do anything at all!
97
+
98
+ #### Using TypeScript with Immutable.js v4
92
99
 
93
- ```javascript
100
+ Immutable.js type definitions embrace ES2015. While Immutable.js itself supports
101
+ legacy browsers and environments, its type definitions require TypeScript's 2015
102
+ lib. Include either `"target": "es2015"` or `"lib": "es2015"` in your
103
+ `tsconfig.json`, or provide `--target es2015` or `--lib es2015` to the
104
+ `tsc` command.
105
+
106
+ <!-- runkit:activate -->
107
+ ```js
108
+ const { Map } = require("immutable");
109
+ const map1 = Map({ a: 1, b: 2, c: 3 });
110
+ const map2 = map1.set('b', 50);
111
+ map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50
112
+ ```
113
+
114
+ #### Using TypeScript with Immutable.js v3 and earlier:
115
+
116
+ Previous versions of Immutable.js include a reference file which you can include
117
+ via relative path to the type definitions at the top of your file.
118
+
119
+ ```js
94
120
  ///<reference path='./node_modules/immutable/dist/immutable.d.ts'/>
95
- import Immutable = require('immutable');
121
+ import Immutable from require('immutable');
96
122
  var map1: Immutable.Map<string, number>;
97
- map1 = Immutable.Map({a:1, b:2, c:3});
123
+ map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
98
124
  var map2 = map1.set('b', 50);
99
125
  map1.get('b'); // 2
100
126
  map2.get('b'); // 50
@@ -122,37 +148,48 @@ When data is passed from above rather than being subscribed to, and you're only
122
148
  interested in doing work when something has changed, you can use equality.
123
149
 
124
150
  Immutable collections should be treated as *values* rather than *objects*. While
125
- objects represents some thing which could change over time, a value represents
151
+ objects represent some thing which could change over time, a value represents
126
152
  the state of that thing at a particular instance of time. This principle is most
127
153
  important to understanding the appropriate use of immutable data. In order to
128
154
  treat Immutable.js collections as values, it's important to use the
129
- `Immutable.is()` function or `.equals()` method to determine value equality
130
- instead of the `===` operator which determines object reference identity.
131
-
132
- ```javascript
133
- var map1 = Immutable.Map({a:1, b:2, c:3});
134
- var map2 = map1.set('b', 2);
135
- assert(map1.equals(map2) === true);
136
- var map3 = map1.set('b', 50);
137
- assert(map1.equals(map3) === false);
155
+ `Immutable.is()` function or `.equals()` method to determine *value equality*
156
+ instead of the `===` operator which determines object *reference identity*.
157
+
158
+ <!-- runkit:activate -->
159
+ ```js
160
+ const { Map } = require('immutable');
161
+ const map1 = Map({ a: 1, b: 2, c: 3 });
162
+ const map2 = Map({ a: 1, b: 2, c: 3 });
163
+ map1.equals(map2); // true
164
+ map1 === map2; // false
138
165
  ```
139
166
 
140
- Note: As a performance optimization `Immutable` attempts to return the existing
167
+ Note: As a performance optimization Immutable.js attempts to return the existing
141
168
  collection when an operation would result in an identical collection, allowing
142
169
  for using `===` reference equality to determine if something definitely has not
143
- changed. This can be extremely useful when used within memoization function
170
+ changed. This can be extremely useful when used within a memoization function
144
171
  which would prefer to re-run the function if a deeper equality check could
145
172
  potentially be more costly. The `===` equality check is also used internally by
146
173
  `Immutable.is` and `.equals()` as a performance optimization.
147
174
 
175
+ <!-- runkit:activate -->
176
+ ```js
177
+ const { Map } = require('immutable');
178
+ const map1 = Map({ a: 1, b: 2, c: 3 });
179
+ const map2 = map1.set('b', 2); // Set to same value
180
+ map1 === map2; // true
181
+ ```
182
+
148
183
  If an object is immutable, it can be "copied" simply by making another reference
149
184
  to it instead of copying the entire object. Because a reference is much smaller
150
185
  than the object itself, this results in memory savings and a potential boost in
151
186
  execution speed for programs which rely on copies (such as an undo-stack).
152
187
 
153
- ```javascript
154
- var map1 = Immutable.Map({a:1, b:2, c:3});
155
- var clone = map1;
188
+ <!-- runkit:activate -->
189
+ ```js
190
+ const { Map } = require('immutable');
191
+ const map = Map({ a: 1, b: 2, c: 3 });
192
+ const mapCopy = map; // Look, "copies" are free!
156
193
  ```
157
194
 
158
195
  [React]: http://facebook.github.io/react/
@@ -162,31 +199,33 @@ var clone = map1;
162
199
  JavaScript-first API
163
200
  --------------------
164
201
 
165
- While `immutable` is inspired by Clojure, Scala, Haskell and other functional
202
+ While Immutable.js is inspired by Clojure, Scala, Haskell and other functional
166
203
  programming environments, it's designed to bring these powerful concepts to
167
204
  JavaScript, and therefore has an Object-Oriented API that closely mirrors that
168
- of [ES6][] [Array][], [Map][], and [Set][].
205
+ of [ES2015][] [Array][], [Map][], and [Set][].
169
206
 
170
- [ES6]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla
207
+ [ES2015]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla
171
208
  [Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
172
209
  [Map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
173
210
  [Set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
174
211
 
175
212
  The difference for the immutable collections is that methods which would mutate
176
- the collection, like `push`, `set`, `unshift` or `splice` instead return a new
177
- immutable collection. Methods which return new arrays like `slice` or `concat`
213
+ the collection, like `push`, `set`, `unshift` or `splice`, instead return a new
214
+ immutable collection. Methods which return new arrays, like `slice` or `concat`,
178
215
  instead return new immutable collections.
179
216
 
180
- ```javascript
181
- var list1 = Immutable.List.of(1, 2);
182
- var list2 = list1.push(3, 4, 5);
183
- var list3 = list2.unshift(0);
184
- var list4 = list1.concat(list2, list3);
185
- assert(list1.size === 2);
186
- assert(list2.size === 5);
187
- assert(list3.size === 6);
188
- assert(list4.size === 13);
189
- assert(list4.get(0) === 1);
217
+ <!-- runkit:activate -->
218
+ ```js
219
+ const { List } = require('immutable');
220
+ const list1 = List([ 1, 2 ]);
221
+ const list2 = list1.push(3, 4, 5);
222
+ const list3 = list2.unshift(0);
223
+ const list4 = list1.concat(list2, list3);
224
+ assert.equal(list1.size, 2);
225
+ assert.equal(list2.size, 5);
226
+ assert.equal(list3.size, 6);
227
+ assert.equal(list4.size, 13);
228
+ assert.equal(list4.get(0), 1);
190
229
  ```
191
230
 
192
231
  Almost all of the methods on [Array][] will be found in similar form on
@@ -194,35 +233,46 @@ Almost all of the methods on [Array][] will be found in similar form on
194
233
  found on `Immutable.Set`, including collection operations like `forEach()`
195
234
  and `map()`.
196
235
 
197
- ```javascript
198
- var alpha = Immutable.Map({a:1, b:2, c:3, d:4});
236
+ <!-- runkit:activate -->
237
+ ```js
238
+ const { Map } = require('immutable');
239
+ const alpha = Map({ a: 1, b: 2, c: 3, d: 4 });
199
240
  alpha.map((v, k) => k.toUpperCase()).join();
200
241
  // 'A,B,C,D'
201
242
  ```
202
243
 
203
- ### Accepts raw JavaScript objects.
244
+ ### Convert from raw JavaScript objects and arrays.
204
245
 
205
- Designed to inter-operate with your existing JavaScript, `immutable`
206
- accepts plain JavaScript Arrays and Objects anywhere a method expects an
207
- `Iterable` with no performance penalty.
246
+ Designed to inter-operate with your existing JavaScript, Immutable.js
247
+ accepts plain JavaScript Arrays and Objects anywhere a method expects a
248
+ `Collection`.
208
249
 
209
- ```javascript
210
- var map1 = Immutable.Map({a:1, b:2, c:3, d:4});
211
- var map2 = Immutable.Map({c:10, a:20, t:30});
212
- var obj = {d:100, o:200, g:300};
213
- var map3 = map1.merge(map2, obj);
250
+ <!-- runkit:activate -->
251
+ ```js
252
+ const { Map, List } = require('immutable');
253
+ const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
254
+ const map2 = Map({ c: 10, a: 20, t: 30 });
255
+ const obj = { d: 100, o: 200, g: 300 };
256
+ const map3 = map1.merge(map2, obj);
214
257
  // Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
258
+ const list1 = List([ 1, 2, 3 ]);
259
+ const list2 = List([ 4, 5, 6 ]);
260
+ const array = [ 7, 8, 9 ];
261
+ const list3 = list1.concat(list2, array);
262
+ // List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
215
263
  ```
216
264
 
217
- This is possible because `immutable` can treat any JavaScript Array or Object
218
- as an Iterable. You can take advantage of this in order to get sophisticated
265
+ This is possible because Immutable.js can treat any JavaScript Array or Object
266
+ as a Collection. You can take advantage of this in order to get sophisticated
219
267
  collection methods on JavaScript Objects, which otherwise have a very sparse
220
268
  native API. Because Seq evaluates lazily and does not cache intermediate
221
269
  results, these operations can be extremely efficient.
222
270
 
223
- ```javascript
224
- var myObject = {a:1,b:2,c:3};
225
- Immutable.Seq(myObject).map(x => x * x).toObject();
271
+ <!-- runkit:activate -->
272
+ ```js
273
+ const { Seq } = require('immutable');
274
+ const myObject = { a: 1, b: 2, c: 3 };
275
+ Seq(myObject).map(x => x * x).toObject();
226
276
  // { a: 1, b: 4, c: 9 }
227
277
  ```
228
278
 
@@ -230,15 +280,16 @@ Keep in mind, when using JS objects to construct Immutable Maps, that
230
280
  JavaScript Object properties are always strings, even if written in a quote-less
231
281
  shorthand, while Immutable Maps accept keys of any type.
232
282
 
283
+ <!-- runkit:activate -->
233
284
  ```js
234
- var obj = { 1: "one" };
235
- Object.keys(obj); // [ "1" ]
236
- obj["1"]; // "one"
237
- obj[1]; // "one"
238
-
239
- var map = Immutable.fromJS(obj);
240
- map.get("1"); // "one"
241
- map.get(1); // undefined
285
+ const { fromJS } = require('immutable');
286
+
287
+ const obj = { 1: "one" };
288
+ console.log(Object.keys(obj)); // [ "1" ]
289
+ console.log(obj["1"], obj[1]); // "one", "one"
290
+
291
+ const map = fromJS(obj);
292
+ console.log(map.get("1"), map.get(1)); // "one", undefined
242
293
  ```
243
294
 
244
295
  Property access for JavaScript Objects first converts the key to a string, but
@@ -248,37 +299,53 @@ not altered.
248
299
 
249
300
  ### Converts back to raw JavaScript objects.
250
301
 
251
- All `immutable` Iterables can be converted to plain JavaScript Arrays and
302
+ All Immutable.js Collections can be converted to plain JavaScript Arrays and
252
303
  Objects shallowly with `toArray()` and `toObject()` or deeply with `toJS()`.
253
- All Immutable Iterables also implement `toJSON()` allowing them to be passed to
254
- `JSON.stringify` directly.
255
-
256
- ```javascript
257
- var deep = Immutable.Map({ a: 1, b: 2, c: Immutable.List.of(3, 4, 5) });
258
- deep.toObject() // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
259
- deep.toArray() // [ 1, 2, List [ 3, 4, 5 ] ]
260
- deep.toJS() // { a: 1, b: 2, c: [ 3, 4, 5 ] }
261
- JSON.stringify(deep) // '{"a":1,"b":2,"c":[3,4,5]}'
304
+ All Immutable Collections also implement `toJSON()` allowing them to be passed
305
+ to `JSON.stringify` directly. They also respect the custom `toJSON()` methods of
306
+ nested objects.
307
+
308
+ <!-- runkit:activate -->
309
+ ```js
310
+ const { Map, List } = require('immutable');
311
+ const deep = Map({ a: 1, b: 2, c: List([ 3, 4, 5 ]) });
312
+ console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
313
+ console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
314
+ console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
315
+ JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'
262
316
  ```
263
317
 
264
- ### Embraces ES6
318
+ ### Embraces ES2015
319
+
320
+ Immutable.js supports all JavaScript environments, including legacy
321
+ browsers (even IE8). However it also takes advantage of features added to
322
+ JavaScript in [ES2015][], the latest standard version of JavaScript, including
323
+ [Iterators][], [Arrow Functions][], [Classes][], and [Modules][]. It's inspired
324
+ by the native [Map][] and [Set][] collections added to ES2015.
325
+
326
+ All examples in the Documentation are presented in ES2015. To run in all
327
+ browsers, they need to be translated to ES5.
265
328
 
266
- `Immutable` takes advantage of features added to JavaScript in [ES6][],
267
- the latest standard version of ECMAScript (JavaScript), including [Iterators][],
268
- [Arrow Functions][], [Classes][], and [Modules][]. It's also inspired by the
269
- [Map][] and [Set][] collections added to ES6. The library is "transpiled" to ES3
270
- in order to support all modern browsers.
329
+ ```js
330
+ // ES2015
331
+ const mapped = foo.map(x => x * x);
332
+ // ES5
333
+ var mapped = foo.map(function (x) { return x * x; });
334
+ ```
271
335
 
272
- All examples are presented in ES6. To run in all browsers, they need to be
273
- translated to ES3.
336
+ All Immutable.js collections are [Iterable][Iterators], which allows them to be
337
+ used anywhere an Iterable is expected, such as when spreading into an Array.
274
338
 
339
+ <!-- runkit:activate -->
275
340
  ```js
276
- // ES6
277
- foo.map(x => x * x);
278
- // ES3
279
- foo.map(function (x) { return x * x; });
341
+ const { List } = require('immutable');
342
+ const aList = List([ 1, 2, 3 ]);
343
+ const anArray = [ 0, ...aList, 4, 5 ]; // [ 0, 1, 2, 3, 4, 5 ]
280
344
  ```
281
345
 
346
+ Note: A Collection is always iterated in the same order, however that order may
347
+ not always be well defined, as is the case for the `Map` and `Set`.
348
+
282
349
  [Iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol
283
350
  [Arrow Functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
284
351
  [Classes]: http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes
@@ -288,11 +355,13 @@ foo.map(function (x) { return x * x; });
288
355
  Nested Structures
289
356
  -----------------
290
357
 
291
- The collections in `immutable` are intended to be nested, allowing for deep
358
+ The collections in Immutable.js are intended to be nested, allowing for deep
292
359
  trees of data, similar to JSON.
293
360
 
294
- ```javascript
295
- var nested = Immutable.fromJS({a:{b:{c:[3,4,5]}}});
361
+ <!-- runkit:activate -->
362
+ ```js
363
+ const { fromJS } = require('immutable');
364
+ const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });
296
365
  // Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }
297
366
  ```
298
367
 
@@ -300,91 +369,119 @@ A few power-tools allow for reading and operating on nested data. The
300
369
  most useful are `mergeDeep`, `getIn`, `setIn`, and `updateIn`, found on `List`,
301
370
  `Map` and `OrderedMap`.
302
371
 
303
- ```javascript
304
- var nested2 = nested.mergeDeep({a:{b:{d:6}}});
372
+ <!-- runkit:activate -->
373
+ ```js
374
+ const { fromJS } = require('immutable');
375
+ const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });
376
+
377
+ const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
305
378
  // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
306
- ```
307
379
 
308
- ```javascript
309
- nested2.getIn(['a', 'b', 'd']); // 6
380
+ console.log(nested2.getIn([ 'a', 'b', 'd' ])); // 6
310
381
 
311
- var nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1);
382
+ const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
383
+ console.log(nested3);
312
384
  // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
313
385
 
314
- var nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6));
386
+ const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
315
387
  // Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
316
388
  ```
317
389
 
318
390
 
319
- Lazy Seq
320
- --------
321
-
322
- `Seq` describes a lazy operation, allowing them to efficiently chain
323
- use of all the Iterable methods (such as `map` and `filter`).
324
-
325
- **Seq is immutable** — Once a Seq is created, it cannot be
326
- changed, appended to, rearranged or otherwise modified. Instead, any mutative
327
- method called on a Seq will return a new Seq.
328
-
329
- **Seq is lazy** — Seq does as little work as necessary to respond to any
330
- method call.
331
-
332
- For example, the following does not perform any work, because the resulting
333
- Seq is never used:
334
-
335
- var oddSquares = Immutable.Seq.of(1,2,3,4,5,6,7,8)
336
- .filter(x => x % 2).map(x => x * x);
391
+ Equality treats Collections as Values
392
+ -------------------------------------
337
393
 
338
- Once the Seq is used, it performs only the work necessary. In this
339
- example, no intermediate arrays are ever created, filter is called three times,
340
- and map is only called twice:
394
+ Immutable.js collections are treated as pure data *values*. Two immutable
395
+ collections are considered *value equal* (via `.equals()` or `is()`) if they
396
+ represent the same collection of values. This differs from JavaScript's typical
397
+ *reference equal* (via `===` or `==`) for Objects and Arrays which only
398
+ determines if two variables represent references to the same object instance.
341
399
 
342
- console.log(oddSquares.get(1)); // 9
400
+ Consider the example below where two identical `Map` instances are not
401
+ *reference equal* but are *value equal*.
343
402
 
344
- Any collection can be converted to a lazy Seq with `.toSeq()`.
403
+ <!-- runkit:activate -->
404
+ ```js
405
+ // First consider:
406
+ const obj1 = { a: 1, b: 2, c: 3 };
407
+ const obj2 = { a: 1, b: 2, c: 3 };
408
+ obj1 !== obj2; // two different instances are always not equal with ===
409
+
410
+ const { Map, is } = require('immutable');
411
+ const map1 = Map({ a: 1, b: 2, c: 3 });
412
+ const map2 = Map({ a: 1, b: 2, c: 3 });
413
+ map1 !== map2; // two different instances are not reference-equal
414
+ map1.equals(map2); // but are value-equal if they have the same values
415
+ is(map1, map2); // alternatively can use the is() function
416
+ ```
345
417
 
346
- var seq = Immutable.Map({a:1, b:1, c:1}).toSeq();
418
+ Value equality allows Immutable.js collections to be used as keys in Maps or
419
+ values in Sets, and retrieved with different but equivalent collections:
347
420
 
348
- Seq allow for the efficient chaining of sequence operations, especially when
349
- converting to a different concrete type (such as to a JS object):
421
+ <!-- runkit:activate -->
422
+ ```js
423
+ const { Map, Set } = require('immutable');
424
+ const map1 = Map({ a: 1, b: 2, c: 3 });
425
+ const map2 = Map({ a: 1, b: 2, c: 3 });
426
+ const set = Set().add(map1);
427
+ set.has(map2); // true because these are value-equal
428
+ ```
350
429
 
351
- seq.flip().map(key => key.toUpperCase()).flip().toObject();
352
- // Map { A: 1, B: 1, C: 1 }
430
+ Note: `is()` uses the same measure of equality as [Object.is][] for scalar
431
+ strings and numbers, but uses value equality for Immutable collections,
432
+ determining if both are immutable and all keys and values are equal
433
+ using the same measure of equality.
353
434
 
354
- As well as expressing logic that would otherwise seem memory-limited:
435
+ [Object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
355
436
 
356
- Immutable.Range(1, Infinity)
357
- .skip(1000)
358
- .map(n => -n)
359
- .filter(n => n % 2 === 0)
360
- .take(2)
361
- .reduce((r, n) => r * n, 1);
362
- // 1006008
437
+ #### Performance tradeoffs
363
438
 
364
- Note: An iterable is always iterated in the same order, however that order may
365
- not always be well defined, as is the case for the `Map`.
439
+ While value equality is useful in many circumstances, it has different
440
+ performance characteristics than reference equality. Understanding these
441
+ tradeoffs may help you decide which to use in each case, especially when used
442
+ to memoize some operation.
366
443
 
444
+ When comparing two collections, value equality may require considering every
445
+ item in each collection, on an `O(N)` time complexity. For large collections of
446
+ values, this could become a costly operation. Though if the two are not equal
447
+ and hardly similar, the inequality is determined very quickly. In contrast, when
448
+ comparing two collections with reference equality, only the initial references
449
+ to memory need to be compared which is not based on the size of the collections,
450
+ which has an `O(1)` time complexity. Checking reference equality is always very
451
+ fast, however just because two collections are not reference-equal does not rule
452
+ out the possibility that they may be value-equal.
367
453
 
368
- Equality treats Collections as Data
369
- -----------------------------------
454
+ #### Return self on no-op optimization
370
455
 
371
- `Immutable` provides equality which treats immutable data structures as pure
372
- data, performing a deep equality check if necessary.
456
+ When possible, Immutable.js avoids creating new objects for updates where no
457
+ change in *value* occurred, to allow for efficient *reference equality* checking
458
+ to quickly determine if no change occurred.
373
459
 
374
- ```javascript
375
- var map1 = Immutable.Map({a:1, b:1, c:1});
376
- var map2 = Immutable.Map({a:1, b:1, c:1});
377
- assert(map1 !== map2); // two different instances
378
- assert(Immutable.is(map1, map2)); // have equivalent values
379
- assert(map1.equals(map2)); // alternatively use the equals method
460
+ <!-- runkit:activate -->
461
+ ```js
462
+ const { Map } = require('immutable');
463
+ const originalMap = Map({ a: 1, b: 2, c: 3 });
464
+ const updatedMap = originalMap.set('b', 2);
465
+ updatedMap === originalMap; // No-op .set() returned the original reference.
380
466
  ```
381
467
 
382
- `Immutable.is()` uses the same measure of equality as [Object.is][]
383
- including if both are immutable and all keys and values are equal
384
- using the same measure of equality.
385
-
386
- [Object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
468
+ However updates which do result in a change will return a new reference. Each
469
+ of these operations occur independently, so two similar updates will not return
470
+ the same reference:
387
471
 
472
+ <!-- runkit:activate -->
473
+ ```js
474
+ const { Map } = require('immutable');
475
+ const originalMap = Map({ a: 1, b: 2, c: 3 });
476
+ const updatedMap = originalMap.set('b', 1000);
477
+ // New instance, leaving the original immutable.
478
+ updatedMap !== originalMap;
479
+ const anotherUpdatedMap = originalMap.set('b', 1000);
480
+ // Despite both the results of the same operation, each created a new reference.
481
+ anotherUpdatedMap !== updatedMap;
482
+ // However the two are value equal.
483
+ anotherUpdatedMap.equals(updatedMap);
484
+ ```
388
485
 
389
486
  Batching Mutations
390
487
  ------------------
@@ -398,24 +495,26 @@ Batching Mutations
398
495
 
399
496
  Applying a mutation to create a new immutable object results in some overhead,
400
497
  which can add up to a minor performance penalty. If you need to apply a series
401
- of mutations locally before returning, `Immutable` gives you the ability to
498
+ of mutations locally before returning, Immutable.js gives you the ability to
402
499
  create a temporary mutable (transient) copy of a collection and apply a batch of
403
500
  mutations in a performant manner by using `withMutations`. In fact, this is
404
- exactly how `Immutable` applies complex mutations itself.
501
+ exactly how Immutable.js applies complex mutations itself.
405
502
 
406
503
  As an example, building `list2` results in the creation of 1, not 3, new
407
504
  immutable Lists.
408
505
 
409
- ```javascript
410
- var list1 = Immutable.List.of(1,2,3);
411
- var list2 = list1.withMutations(function (list) {
506
+ <!-- runkit:activate -->
507
+ ```js
508
+ const { List } = require('immutable');
509
+ const list1 = List([ 1, 2, 3 ]);
510
+ const list2 = list1.withMutations(function (list) {
412
511
  list.push(4).push(5).push(6);
413
512
  });
414
- assert(list1.size === 3);
415
- assert(list2.size === 6);
513
+ assert.equal(list1.size, 3);
514
+ assert.equal(list2.size, 6);
416
515
  ```
417
516
 
418
- Note: `immutable` also provides `asMutable` and `asImmutable`, but only
517
+ Note: Immutable.js also provides `asMutable` and `asImmutable`, but only
419
518
  encourages their use when `withMutations` will not suffice. Use caution to not
420
519
  return a mutable copy, which could result in undesired behavior.
421
520
 
@@ -426,6 +525,76 @@ and `splice` will always return new immutable data-structures and never mutate
426
525
  a mutable collection.
427
526
 
428
527
 
528
+ Lazy Seq
529
+ --------
530
+
531
+ `Seq` describes a lazy operation, allowing them to efficiently chain
532
+ use of all the higher-order collection methods (such as `map` and `filter`)
533
+ by not creating intermediate collections.
534
+
535
+ **Seq is immutable** — Once a Seq is created, it cannot be
536
+ changed, appended to, rearranged or otherwise modified. Instead, any mutative
537
+ method called on a `Seq` will return a new `Seq`.
538
+
539
+ **Seq is lazy** — `Seq` does as little work as necessary to respond to any
540
+ method call. Values are often created during iteration, including implicit
541
+ iteration when reducing or converting to a concrete data structure such as
542
+ a `List` or JavaScript `Array`.
543
+
544
+ For example, the following performs no work, because the resulting
545
+ `Seq`'s values are never iterated:
546
+
547
+ ```js
548
+ const { Seq } = require('immutable');
549
+ const oddSquares = Seq([ 1, 2, 3, 4, 5, 6, 7, 8 ])
550
+ .filter(x => x % 2 !== 0)
551
+ .map(x => x * x);
552
+ ```
553
+
554
+ Once the `Seq` is used, it performs only the work necessary. In this
555
+ example, no intermediate arrays are ever created, filter is called three
556
+ times, and map is only called once:
557
+
558
+ ```js
559
+ oddSquares.get(1); // 9
560
+ ```
561
+
562
+ Any collection can be converted to a lazy Seq with `Seq()`.
563
+
564
+ <!-- runkit:activate -->
565
+ ```js
566
+ const { Map, Seq } = require('immutable');
567
+ const map = Map({ a: 1, b: 2, c: 3 });
568
+ const lazySeq = Seq(map);
569
+ ```
570
+
571
+ `Seq` allows for the efficient chaining of operations, allowing for the
572
+ expression of logic that can otherwise be very tedious:
573
+
574
+ ```js
575
+ lazySeq
576
+ .flip()
577
+ .map(key => key.toUpperCase())
578
+ .flip();
579
+ // Seq { A: 1, B: 1, C: 1 }
580
+ ```
581
+
582
+ As well as expressing logic that would otherwise seem memory or time
583
+ limited, for example `Range` is a special kind of Lazy sequence.
584
+
585
+ <!-- runkit:activate -->
586
+ ```js
587
+ const { Range } = require('immutable');
588
+ Range(1, Infinity)
589
+ .skip(1000)
590
+ .map(n => -n)
591
+ .filter(n => n % 2 === 0)
592
+ .take(2)
593
+ .reduce((r, n) => r * n, 1);
594
+ // 1006008
595
+ ```
596
+
597
+
429
598
  Documentation
430
599
  -------------
431
600
 
@@ -441,7 +610,7 @@ contains articles on specific topics. Can't find something? Open an [issue](http
441
610
  Testing
442
611
  -------
443
612
 
444
- 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` collections.
613
+ 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.
445
614
 
446
615
 
447
616
  Contribution
@@ -449,7 +618,7 @@ Contribution
449
618
 
450
619
  Use [Github issues](https://github.com/facebook/immutable-js/issues) for requests.
451
620
 
452
- We actively welcome pull requests, learn how to [contribute](./CONTRIBUTING.md).
621
+ We actively welcome pull requests, learn how to [contribute](https://github.com/facebook/immutable-js/blob/master/.github/CONTRIBUTING.md).
453
622
 
454
623
 
455
624
  Changelog