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