immutable 4.0.0-rc.9 → 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/LICENSE +1 -1
- package/README.md +255 -174
- package/dist/immutable.d.ts +1160 -677
- package/dist/immutable.es.js +809 -635
- package/dist/immutable.js +5100 -4917
- package/dist/immutable.js.flow +972 -287
- package/dist/immutable.min.js +53 -36
- package/package.json +8 -98
- package/contrib/cursor/README.md +0 -43
- package/contrib/cursor/__tests__/Cursor.ts.skip +0 -395
- package/contrib/cursor/index.d.ts +0 -287
- package/contrib/cursor/index.js +0 -360
- package/dist/immutable-nonambient.d.ts +0 -5149
package/README.md
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
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)
|
|
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
|
-
|
|
26
|
-
|
|
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
|
|
45
|
+
[](https://youtu.be/I7IdS-PbEgI)
|
|
31
46
|
|
|
47
|
+
[README.md]: https://github.com/immutable-js/immutable-js/blob/main/README.md
|
|
48
|
+
[immutable.d.ts]: https://github.com/immutable-js/immutable-js/blob/main/type-definitions/immutable.d.ts
|
|
49
|
+
[wiki]: https://github.com/immutable-js/immutable-js/wiki
|
|
50
|
+
[issue]: https://github.com/immutable-js/immutable-js/issues
|
|
51
|
+
[Persistent]: https://en.wikipedia.org/wiki/Persistent_data_structure
|
|
52
|
+
[Immutable]: https://en.wikipedia.org/wiki/Immutable_object
|
|
53
|
+
[hash maps tries]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie
|
|
54
|
+
[vector tries]: https://hypirion.com/musings/understanding-persistent-vector-pt-1
|
|
32
55
|
|
|
33
|
-
Getting started
|
|
34
|
-
---------------
|
|
56
|
+
## Getting started
|
|
35
57
|
|
|
36
58
|
Install `immutable` using npm.
|
|
37
59
|
|
|
@@ -39,14 +61,21 @@ 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') +
|
|
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
|
|
@@ -55,7 +84,7 @@ Immutable.js has no dependencies, which makes it predictable to include in a Bro
|
|
|
55
84
|
|
|
56
85
|
It's highly recommended to use a module bundler like [webpack](https://webpack.github.io/),
|
|
57
86
|
[rollup](https://rollupjs.org/), or
|
|
58
|
-
[browserify](
|
|
87
|
+
[browserify](https://browserify.org/). The `immutable` npm module works
|
|
59
88
|
without any additional consideration. All examples throughout the documentation
|
|
60
89
|
will assume use of this kind of tool.
|
|
61
90
|
|
|
@@ -68,18 +97,18 @@ Use a script tag to directly add `Immutable` to the global scope:
|
|
|
68
97
|
```html
|
|
69
98
|
<script src="immutable.min.js"></script>
|
|
70
99
|
<script>
|
|
71
|
-
var map1 = Immutable.Map({a:1, b:2, c:3});
|
|
100
|
+
var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
|
|
72
101
|
var map2 = map1.set('b', 50);
|
|
73
102
|
map1.get('b'); // 2
|
|
74
103
|
map2.get('b'); // 50
|
|
75
104
|
</script>
|
|
76
105
|
```
|
|
77
106
|
|
|
78
|
-
Or use an AMD-style loader (such as [RequireJS](
|
|
107
|
+
Or use an AMD-style loader (such as [RequireJS](https://requirejs.org/)):
|
|
79
108
|
|
|
80
109
|
```js
|
|
81
110
|
require(['./immutable.min.js'], function (Immutable) {
|
|
82
|
-
var map1 = Immutable.Map({a:1, b:2, c:3});
|
|
111
|
+
var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
|
|
83
112
|
var map2 = map1.set('b', 50);
|
|
84
113
|
map1.get('b'); // 2
|
|
85
114
|
map2.get('b'); // 50
|
|
@@ -89,7 +118,7 @@ require(['./immutable.min.js'], function (Immutable) {
|
|
|
89
118
|
### Flow & TypeScript
|
|
90
119
|
|
|
91
120
|
Use these Immutable collections and sequences as you would use native
|
|
92
|
-
collections in your [Flowtype](https://flowtype.org/) or [TypeScript](
|
|
121
|
+
collections in your [Flowtype](https://flowtype.org/) or [TypeScript](https://typescriptlang.org) programs while still taking
|
|
93
122
|
advantage of type generics, error detection, and auto-complete in your IDE.
|
|
94
123
|
|
|
95
124
|
Installing `immutable` via npm brings with it type definitions for Flow (v0.55.0 or higher)
|
|
@@ -104,11 +133,12 @@ lib. Include either `"target": "es2015"` or `"lib": "es2015"` in your
|
|
|
104
133
|
`tsc` command.
|
|
105
134
|
|
|
106
135
|
<!-- runkit:activate -->
|
|
136
|
+
|
|
107
137
|
```js
|
|
108
|
-
const { Map } = require(
|
|
138
|
+
const { Map } = require('immutable');
|
|
109
139
|
const map1 = Map({ a: 1, b: 2, c: 3 });
|
|
110
140
|
const map2 = map1.set('b', 50);
|
|
111
|
-
map1.get('b') +
|
|
141
|
+
map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50
|
|
112
142
|
```
|
|
113
143
|
|
|
114
144
|
#### Using TypeScript with Immutable.js v3 and earlier:
|
|
@@ -118,17 +148,15 @@ via relative path to the type definitions at the top of your file.
|
|
|
118
148
|
|
|
119
149
|
```js
|
|
120
150
|
///<reference path='./node_modules/immutable/dist/immutable.d.ts'/>
|
|
121
|
-
import Immutable from
|
|
151
|
+
import Immutable from 'immutable';
|
|
122
152
|
var map1: Immutable.Map<string, number>;
|
|
123
|
-
map1 = Immutable.Map({a:1, b:2, c:3});
|
|
153
|
+
map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
|
|
124
154
|
var map2 = map1.set('b', 50);
|
|
125
155
|
map1.get('b'); // 2
|
|
126
156
|
map2.get('b'); // 50
|
|
127
157
|
```
|
|
128
158
|
|
|
129
|
-
|
|
130
|
-
The case for Immutability
|
|
131
|
-
-------------------------
|
|
159
|
+
## The case for Immutability
|
|
132
160
|
|
|
133
161
|
Much of what makes application development difficult is tracking mutation and
|
|
134
162
|
maintaining state. Developing with immutable data encourages you to think
|
|
@@ -147,23 +175,22 @@ and especially well with an application designed using the ideas of [Flux][].
|
|
|
147
175
|
When data is passed from above rather than being subscribed to, and you're only
|
|
148
176
|
interested in doing work when something has changed, you can use equality.
|
|
149
177
|
|
|
150
|
-
Immutable collections should be treated as
|
|
178
|
+
Immutable collections should be treated as _values_ rather than _objects_. While
|
|
151
179
|
objects represent some thing which could change over time, a value represents
|
|
152
180
|
the state of that thing at a particular instance of time. This principle is most
|
|
153
181
|
important to understanding the appropriate use of immutable data. In order to
|
|
154
182
|
treat Immutable.js collections as values, it's important to use the
|
|
155
|
-
`Immutable.is()` function or `.equals()` method to determine
|
|
156
|
-
instead of the `===` operator which determines object
|
|
183
|
+
`Immutable.is()` function or `.equals()` method to determine _value equality_
|
|
184
|
+
instead of the `===` operator which determines object _reference identity_.
|
|
157
185
|
|
|
158
186
|
<!-- runkit:activate -->
|
|
187
|
+
|
|
159
188
|
```js
|
|
160
|
-
const { Map } = require('immutable')
|
|
161
|
-
const map1 = Map(
|
|
162
|
-
const map2 =
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const map3 = map1.set('b', 50)
|
|
166
|
-
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
|
|
167
194
|
```
|
|
168
195
|
|
|
169
196
|
Note: As a performance optimization Immutable.js attempts to return the existing
|
|
@@ -174,34 +201,43 @@ which would prefer to re-run the function if a deeper equality check could
|
|
|
174
201
|
potentially be more costly. The `===` equality check is also used internally by
|
|
175
202
|
`Immutable.is` and `.equals()` as a performance optimization.
|
|
176
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
|
+
|
|
177
213
|
If an object is immutable, it can be "copied" simply by making another reference
|
|
178
214
|
to it instead of copying the entire object. Because a reference is much smaller
|
|
179
215
|
than the object itself, this results in memory savings and a potential boost in
|
|
180
216
|
execution speed for programs which rely on copies (such as an undo-stack).
|
|
181
217
|
|
|
182
218
|
<!-- runkit:activate -->
|
|
219
|
+
|
|
183
220
|
```js
|
|
184
|
-
const { Map } = require('immutable')
|
|
185
|
-
const
|
|
186
|
-
const
|
|
221
|
+
const { Map } = require('immutable');
|
|
222
|
+
const map = Map({ a: 1, b: 2, c: 3 });
|
|
223
|
+
const mapCopy = map; // Look, "copies" are free!
|
|
187
224
|
```
|
|
188
225
|
|
|
189
|
-
[React]:
|
|
190
|
-
[Flux]:
|
|
226
|
+
[React]: https://reactjs.org/
|
|
227
|
+
[Flux]: https://facebook.github.io/flux/docs/in-depth-overview/
|
|
191
228
|
|
|
192
229
|
|
|
193
|
-
JavaScript-first API
|
|
194
|
-
--------------------
|
|
230
|
+
## JavaScript-first API
|
|
195
231
|
|
|
196
232
|
While Immutable.js is inspired by Clojure, Scala, Haskell and other functional
|
|
197
233
|
programming environments, it's designed to bring these powerful concepts to
|
|
198
234
|
JavaScript, and therefore has an Object-Oriented API that closely mirrors that
|
|
199
235
|
of [ES2015][] [Array][], [Map][], and [Set][].
|
|
200
236
|
|
|
201
|
-
[
|
|
202
|
-
[
|
|
203
|
-
[
|
|
204
|
-
[
|
|
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
|
|
205
241
|
|
|
206
242
|
The difference for the immutable collections is that methods which would mutate
|
|
207
243
|
the collection, like `push`, `set`, `unshift` or `splice`, instead return a new
|
|
@@ -209,9 +245,10 @@ immutable collection. Methods which return new arrays, like `slice` or `concat`,
|
|
|
209
245
|
instead return new immutable collections.
|
|
210
246
|
|
|
211
247
|
<!-- runkit:activate -->
|
|
248
|
+
|
|
212
249
|
```js
|
|
213
|
-
const { List } = require('immutable')
|
|
214
|
-
const list1 = List([
|
|
250
|
+
const { List } = require('immutable');
|
|
251
|
+
const list1 = List([1, 2]);
|
|
215
252
|
const list2 = list1.push(3, 4, 5);
|
|
216
253
|
const list3 = list2.unshift(0);
|
|
217
254
|
const list4 = list1.concat(list2, list3);
|
|
@@ -228,8 +265,9 @@ found on `Immutable.Set`, including collection operations like `forEach()`
|
|
|
228
265
|
and `map()`.
|
|
229
266
|
|
|
230
267
|
<!-- runkit:activate -->
|
|
268
|
+
|
|
231
269
|
```js
|
|
232
|
-
const { Map } = require('immutable')
|
|
270
|
+
const { Map } = require('immutable');
|
|
233
271
|
const alpha = Map({ a: 1, b: 2, c: 3, d: 4 });
|
|
234
272
|
alpha.map((v, k) => k.toUpperCase()).join();
|
|
235
273
|
// 'A,B,C,D'
|
|
@@ -238,21 +276,22 @@ alpha.map((v, k) => k.toUpperCase()).join();
|
|
|
238
276
|
### Convert from raw JavaScript objects and arrays.
|
|
239
277
|
|
|
240
278
|
Designed to inter-operate with your existing JavaScript, Immutable.js
|
|
241
|
-
accepts plain JavaScript Arrays and Objects anywhere a method expects
|
|
279
|
+
accepts plain JavaScript Arrays and Objects anywhere a method expects a
|
|
242
280
|
`Collection`.
|
|
243
281
|
|
|
244
282
|
<!-- runkit:activate -->
|
|
283
|
+
|
|
245
284
|
```js
|
|
246
|
-
const { Map, List } = require('immutable')
|
|
247
|
-
const map1 = Map({ a: 1, b: 2, c: 3, d: 4 })
|
|
248
|
-
const map2 = Map({ c: 10, a: 20, t: 30 })
|
|
249
|
-
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 };
|
|
250
289
|
const map3 = map1.merge(map2, obj);
|
|
251
290
|
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
|
|
252
|
-
const list1 = List([
|
|
253
|
-
const list2 = List([
|
|
254
|
-
const array = [
|
|
255
|
-
const list3 = list1.concat(list2, array)
|
|
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);
|
|
256
295
|
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
|
257
296
|
```
|
|
258
297
|
|
|
@@ -263,10 +302,13 @@ native API. Because Seq evaluates lazily and does not cache intermediate
|
|
|
263
302
|
results, these operations can be extremely efficient.
|
|
264
303
|
|
|
265
304
|
<!-- runkit:activate -->
|
|
305
|
+
|
|
266
306
|
```js
|
|
267
|
-
const { Seq } = require('immutable')
|
|
268
|
-
const myObject = { a: 1, b: 2, c: 3 }
|
|
269
|
-
Seq(myObject)
|
|
307
|
+
const { Seq } = require('immutable');
|
|
308
|
+
const myObject = { a: 1, b: 2, c: 3 };
|
|
309
|
+
Seq(myObject)
|
|
310
|
+
.map(x => x * x)
|
|
311
|
+
.toObject();
|
|
270
312
|
// { a: 1, b: 4, c: 9 }
|
|
271
313
|
```
|
|
272
314
|
|
|
@@ -275,43 +317,45 @@ JavaScript Object properties are always strings, even if written in a quote-less
|
|
|
275
317
|
shorthand, while Immutable Maps accept keys of any type.
|
|
276
318
|
|
|
277
319
|
<!-- runkit:activate -->
|
|
320
|
+
|
|
278
321
|
```js
|
|
279
|
-
const { fromJS } = require('immutable')
|
|
322
|
+
const { fromJS } = require('immutable');
|
|
280
323
|
|
|
281
|
-
const obj = { 1:
|
|
282
|
-
Object.keys(obj) // [ "1" ]
|
|
283
|
-
|
|
324
|
+
const obj = { 1: 'one' };
|
|
325
|
+
console.log(Object.keys(obj)); // [ "1" ]
|
|
326
|
+
console.log(obj['1'], obj[1]); // "one", "one"
|
|
284
327
|
|
|
285
|
-
const map = fromJS(obj)
|
|
286
|
-
|
|
328
|
+
const map = fromJS(obj);
|
|
329
|
+
console.log(map.get('1'), map.get(1)); // "one", undefined
|
|
287
330
|
```
|
|
288
331
|
|
|
289
332
|
Property access for JavaScript Objects first converts the key to a string, but
|
|
290
333
|
since Immutable Map keys can be of any type the argument to `get()` is
|
|
291
334
|
not altered.
|
|
292
335
|
|
|
293
|
-
|
|
294
336
|
### Converts back to raw JavaScript objects.
|
|
295
337
|
|
|
296
338
|
All Immutable.js Collections can be converted to plain JavaScript Arrays and
|
|
297
339
|
Objects shallowly with `toArray()` and `toObject()` or deeply with `toJS()`.
|
|
298
340
|
All Immutable Collections also implement `toJSON()` allowing them to be passed
|
|
299
|
-
to `JSON.stringify` directly.
|
|
341
|
+
to `JSON.stringify` directly. They also respect the custom `toJSON()` methods of
|
|
342
|
+
nested objects.
|
|
300
343
|
|
|
301
344
|
<!-- runkit:activate -->
|
|
345
|
+
|
|
302
346
|
```js
|
|
303
|
-
const { Map, List } = require('immutable')
|
|
304
|
-
const deep = Map({ a: 1, b: 2, c: List([
|
|
305
|
-
console.log(deep.toObject()) // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
|
|
306
|
-
console.log(deep.toArray()) // [ 1, 2, List [ 3, 4, 5 ] ]
|
|
307
|
-
console.log(deep.toJS()) // { a: 1, b: 2, c: [ 3, 4, 5 ] }
|
|
308
|
-
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]}'
|
|
309
353
|
```
|
|
310
354
|
|
|
311
355
|
### Embraces ES2015
|
|
312
356
|
|
|
313
357
|
Immutable.js supports all JavaScript environments, including legacy
|
|
314
|
-
browsers (even
|
|
358
|
+
browsers (even IE11). However it also takes advantage of features added to
|
|
315
359
|
JavaScript in [ES2015][], the latest standard version of JavaScript, including
|
|
316
360
|
[Iterators][], [Arrow Functions][], [Classes][], and [Modules][]. It's inspired
|
|
317
361
|
by the native [Map][] and [Set][] collections added to ES2015.
|
|
@@ -323,17 +367,20 @@ browsers, they need to be translated to ES5.
|
|
|
323
367
|
// ES2015
|
|
324
368
|
const mapped = foo.map(x => x * x);
|
|
325
369
|
// ES5
|
|
326
|
-
var mapped = foo.map(function (x) {
|
|
370
|
+
var mapped = foo.map(function (x) {
|
|
371
|
+
return x * x;
|
|
372
|
+
});
|
|
327
373
|
```
|
|
328
374
|
|
|
329
|
-
All Immutable.js collections are [Iterable][
|
|
375
|
+
All Immutable.js collections are [Iterable][iterators], which allows them to be
|
|
330
376
|
used anywhere an Iterable is expected, such as when spreading into an Array.
|
|
331
377
|
|
|
332
378
|
<!-- runkit:activate -->
|
|
379
|
+
|
|
333
380
|
```js
|
|
334
|
-
const { List } = require('immutable')
|
|
335
|
-
const aList = List([
|
|
336
|
-
const anArray = [
|
|
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 ]
|
|
337
384
|
```
|
|
338
385
|
|
|
339
386
|
Note: A Collection is always iterated in the same order, however that order may
|
|
@@ -341,20 +388,20 @@ not always be well defined, as is the case for the `Map` and `Set`.
|
|
|
341
388
|
|
|
342
389
|
[Iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol
|
|
343
390
|
[Arrow Functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
|
344
|
-
[Classes]:
|
|
345
|
-
[Modules]:
|
|
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
|
|
346
393
|
|
|
347
394
|
|
|
348
|
-
Nested Structures
|
|
349
|
-
-----------------
|
|
395
|
+
## Nested Structures
|
|
350
396
|
|
|
351
397
|
The collections in Immutable.js are intended to be nested, allowing for deep
|
|
352
398
|
trees of data, similar to JSON.
|
|
353
399
|
|
|
354
400
|
<!-- runkit:activate -->
|
|
401
|
+
|
|
355
402
|
```js
|
|
356
|
-
const { fromJS } = require('immutable')
|
|
357
|
-
const nested = fromJS({ a: { b: { c: [
|
|
403
|
+
const { fromJS } = require('immutable');
|
|
404
|
+
const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
|
|
358
405
|
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }
|
|
359
406
|
```
|
|
360
407
|
|
|
@@ -363,61 +410,62 @@ most useful are `mergeDeep`, `getIn`, `setIn`, and `updateIn`, found on `List`,
|
|
|
363
410
|
`Map` and `OrderedMap`.
|
|
364
411
|
|
|
365
412
|
<!-- runkit:activate -->
|
|
413
|
+
|
|
366
414
|
```js
|
|
367
|
-
const { fromJS } = require('immutable')
|
|
368
|
-
const nested = fromJS({ a: { b: { c: [
|
|
415
|
+
const { fromJS } = require('immutable');
|
|
416
|
+
const nested = fromJS({ a: { b: { c: [3, 4, 5] } } });
|
|
369
417
|
|
|
370
|
-
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } })
|
|
418
|
+
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
|
|
371
419
|
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
|
|
372
420
|
|
|
373
|
-
console.log(nested2.getIn([
|
|
421
|
+
console.log(nested2.getIn(['a', 'b', 'd'])); // 6
|
|
374
422
|
|
|
375
|
-
const nested3 = nested2.updateIn([
|
|
423
|
+
const nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1);
|
|
376
424
|
console.log(nested3);
|
|
377
425
|
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
|
|
378
426
|
|
|
379
|
-
const nested4 = nested3.updateIn([
|
|
427
|
+
const nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6));
|
|
380
428
|
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
|
|
381
429
|
```
|
|
382
430
|
|
|
431
|
+
## Equality treats Collections as Values
|
|
383
432
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
Immutable.js collections are treated as pure data *values*. Two immutable
|
|
388
|
-
collections are considered *value equal* (via `.equals()` or `is()`) if they
|
|
433
|
+
Immutable.js collections are treated as pure data _values_. Two immutable
|
|
434
|
+
collections are considered _value equal_ (via `.equals()` or `is()`) if they
|
|
389
435
|
represent the same collection of values. This differs from JavaScript's typical
|
|
390
|
-
|
|
436
|
+
_reference equal_ (via `===` or `==`) for Objects and Arrays which only
|
|
391
437
|
determines if two variables represent references to the same object instance.
|
|
392
438
|
|
|
393
439
|
Consider the example below where two identical `Map` instances are not
|
|
394
|
-
|
|
440
|
+
_reference equal_ but are _value equal_.
|
|
395
441
|
|
|
396
442
|
<!-- runkit:activate -->
|
|
443
|
+
|
|
397
444
|
```js
|
|
398
445
|
// First consider:
|
|
399
|
-
const obj1 = { a: 1, b: 2, c: 3 }
|
|
400
|
-
const obj2 = { a: 1, b: 2, c: 3 }
|
|
401
|
-
obj1 !== obj2 // two different instances are always not equal with ===
|
|
402
|
-
|
|
403
|
-
const { Map, is } = require('immutable')
|
|
404
|
-
const map1 = Map({ a: 1, b: 2, c: 3 })
|
|
405
|
-
const map2 = Map({ a: 1, b: 2, c: 3 })
|
|
406
|
-
map1 !== map2 // two different instances are not reference-equal
|
|
407
|
-
map1.equals(map2) // but are value-equal if they have the same values
|
|
408
|
-
is(map1, map2) // alternatively can use the is() function
|
|
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 ===
|
|
449
|
+
|
|
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
|
|
409
456
|
```
|
|
410
457
|
|
|
411
458
|
Value equality allows Immutable.js collections to be used as keys in Maps or
|
|
412
459
|
values in Sets, and retrieved with different but equivalent collections:
|
|
413
460
|
|
|
414
461
|
<!-- runkit:activate -->
|
|
462
|
+
|
|
415
463
|
```js
|
|
416
|
-
const { Map, Set } = require('immutable')
|
|
417
|
-
const map1 = Map({ a: 1, b: 2, c: 3 })
|
|
418
|
-
const map2 = Map({ a: 1, b: 2, c: 3 })
|
|
419
|
-
const set = Set().add(map1)
|
|
420
|
-
set.has(map2) // true because these are value-equal
|
|
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
|
|
421
469
|
```
|
|
422
470
|
|
|
423
471
|
Note: `is()` uses the same measure of equality as [Object.is][] for scalar
|
|
@@ -425,7 +473,7 @@ strings and numbers, but uses value equality for Immutable collections,
|
|
|
425
473
|
determining if both are immutable and all keys and values are equal
|
|
426
474
|
using the same measure of equality.
|
|
427
475
|
|
|
428
|
-
[
|
|
476
|
+
[object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
|
429
477
|
|
|
430
478
|
#### Performance tradeoffs
|
|
431
479
|
|
|
@@ -447,15 +495,16 @@ out the possibility that they may be value-equal.
|
|
|
447
495
|
#### Return self on no-op optimization
|
|
448
496
|
|
|
449
497
|
When possible, Immutable.js avoids creating new objects for updates where no
|
|
450
|
-
change in
|
|
498
|
+
change in _value_ occurred, to allow for efficient _reference equality_ checking
|
|
451
499
|
to quickly determine if no change occurred.
|
|
452
500
|
|
|
453
501
|
<!-- runkit:activate -->
|
|
502
|
+
|
|
454
503
|
```js
|
|
455
|
-
const { Map } = require('immutable')
|
|
456
|
-
const originalMap = Map({ a: 1, b: 2, c: 3 })
|
|
457
|
-
const updatedMap = originalMap.set('b', 2)
|
|
458
|
-
updatedMap === originalMap // No-op .set() returned the original reference.
|
|
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.
|
|
459
508
|
```
|
|
460
509
|
|
|
461
510
|
However updates which do result in a change will return a new reference. Each
|
|
@@ -463,21 +512,21 @@ of these operations occur independently, so two similar updates will not return
|
|
|
463
512
|
the same reference:
|
|
464
513
|
|
|
465
514
|
<!-- runkit:activate -->
|
|
515
|
+
|
|
466
516
|
```js
|
|
467
|
-
const { Map } = require('immutable')
|
|
468
|
-
const originalMap = Map({ a: 1, b: 2, c: 3 })
|
|
469
|
-
const updatedMap = originalMap.set('b', 1000)
|
|
517
|
+
const { Map } = require('immutable');
|
|
518
|
+
const originalMap = Map({ a: 1, b: 2, c: 3 });
|
|
519
|
+
const updatedMap = originalMap.set('b', 1000);
|
|
470
520
|
// New instance, leaving the original immutable.
|
|
471
|
-
updatedMap !== originalMap
|
|
472
|
-
const anotherUpdatedMap = originalMap.set('b', 1000)
|
|
521
|
+
updatedMap !== originalMap;
|
|
522
|
+
const anotherUpdatedMap = originalMap.set('b', 1000);
|
|
473
523
|
// Despite both the results of the same operation, each created a new reference.
|
|
474
|
-
anotherUpdatedMap !== updatedMap
|
|
524
|
+
anotherUpdatedMap !== updatedMap;
|
|
475
525
|
// However the two are value equal.
|
|
476
|
-
anotherUpdatedMap.equals(updatedMap)
|
|
526
|
+
anotherUpdatedMap.equals(updatedMap);
|
|
477
527
|
```
|
|
478
528
|
|
|
479
|
-
Batching Mutations
|
|
480
|
-
------------------
|
|
529
|
+
## Batching Mutations
|
|
481
530
|
|
|
482
531
|
> If a tree falls in the woods, does it make a sound?
|
|
483
532
|
>
|
|
@@ -491,15 +540,16 @@ which can add up to a minor performance penalty. If you need to apply a series
|
|
|
491
540
|
of mutations locally before returning, Immutable.js gives you the ability to
|
|
492
541
|
create a temporary mutable (transient) copy of a collection and apply a batch of
|
|
493
542
|
mutations in a performant manner by using `withMutations`. In fact, this is
|
|
494
|
-
exactly how
|
|
543
|
+
exactly how Immutable.js applies complex mutations itself.
|
|
495
544
|
|
|
496
545
|
As an example, building `list2` results in the creation of 1, not 3, new
|
|
497
546
|
immutable Lists.
|
|
498
547
|
|
|
499
548
|
<!-- runkit:activate -->
|
|
549
|
+
|
|
500
550
|
```js
|
|
501
|
-
const { List } = require('immutable')
|
|
502
|
-
const list1 = List([
|
|
551
|
+
const { List } = require('immutable');
|
|
552
|
+
const list1 = List([1, 2, 3]);
|
|
503
553
|
const list2 = list1.withMutations(function (list) {
|
|
504
554
|
list.push(4).push(5).push(6);
|
|
505
555
|
});
|
|
@@ -511,15 +561,13 @@ Note: Immutable.js also provides `asMutable` and `asImmutable`, but only
|
|
|
511
561
|
encourages their use when `withMutations` will not suffice. Use caution to not
|
|
512
562
|
return a mutable copy, which could result in undesired behavior.
|
|
513
563
|
|
|
514
|
-
|
|
564
|
+
_Important!_: Only a select few methods can be used in `withMutations` including
|
|
515
565
|
`set`, `push` and `pop`. These methods can be applied directly against a
|
|
516
566
|
persistent data-structure where other methods like `map`, `filter`, `sort`,
|
|
517
567
|
and `splice` will always return new immutable data-structures and never mutate
|
|
518
568
|
a mutable collection.
|
|
519
569
|
|
|
520
|
-
|
|
521
|
-
Lazy Seq
|
|
522
|
-
--------
|
|
570
|
+
## Lazy Seq
|
|
523
571
|
|
|
524
572
|
`Seq` describes a lazy operation, allowing them to efficiently chain
|
|
525
573
|
use of all the higher-order collection methods (such as `map` and `filter`)
|
|
@@ -538,10 +586,10 @@ For example, the following performs no work, because the resulting
|
|
|
538
586
|
`Seq`'s values are never iterated:
|
|
539
587
|
|
|
540
588
|
```js
|
|
541
|
-
const { Seq } = require('immutable')
|
|
542
|
-
const oddSquares = Seq([
|
|
589
|
+
const { Seq } = require('immutable');
|
|
590
|
+
const oddSquares = Seq([1, 2, 3, 4, 5, 6, 7, 8])
|
|
543
591
|
.filter(x => x % 2 !== 0)
|
|
544
|
-
.map(x => x * x)
|
|
592
|
+
.map(x => x * x);
|
|
545
593
|
```
|
|
546
594
|
|
|
547
595
|
Once the `Seq` is used, it performs only the work necessary. In this
|
|
@@ -555,10 +603,11 @@ oddSquares.get(1); // 9
|
|
|
555
603
|
Any collection can be converted to a lazy Seq with `Seq()`.
|
|
556
604
|
|
|
557
605
|
<!-- runkit:activate -->
|
|
606
|
+
|
|
558
607
|
```js
|
|
559
|
-
const { Map } = require('immutable')
|
|
560
|
-
const map = Map({ a: 1, b: 2, c: 3 }
|
|
561
|
-
const lazySeq = Seq(map)
|
|
608
|
+
const { Map, Seq } = require('immutable');
|
|
609
|
+
const map = Map({ a: 1, b: 2, c: 3 });
|
|
610
|
+
const lazySeq = Seq(map);
|
|
562
611
|
```
|
|
563
612
|
|
|
564
613
|
`Seq` allows for the efficient chaining of operations, allowing for the
|
|
@@ -568,69 +617,101 @@ expression of logic that can otherwise be very tedious:
|
|
|
568
617
|
lazySeq
|
|
569
618
|
.flip()
|
|
570
619
|
.map(key => key.toUpperCase())
|
|
571
|
-
.flip()
|
|
572
|
-
// Seq { A: 1, B:
|
|
620
|
+
.flip();
|
|
621
|
+
// Seq { A: 1, B: 2, C: 3 }
|
|
573
622
|
```
|
|
574
623
|
|
|
575
624
|
As well as expressing logic that would otherwise seem memory or time
|
|
576
625
|
limited, for example `Range` is a special kind of Lazy sequence.
|
|
577
626
|
|
|
578
627
|
<!-- runkit:activate -->
|
|
628
|
+
|
|
579
629
|
```js
|
|
580
|
-
const { Range } = require('immutable')
|
|
630
|
+
const { Range } = require('immutable');
|
|
581
631
|
Range(1, Infinity)
|
|
582
632
|
.skip(1000)
|
|
583
633
|
.map(n => -n)
|
|
584
634
|
.filter(n => n % 2 === 0)
|
|
585
635
|
.take(2)
|
|
586
|
-
.reduce((r, n) => r * n, 1)
|
|
636
|
+
.reduce((r, n) => r * n, 1);
|
|
587
637
|
// 1006008
|
|
588
638
|
```
|
|
589
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.
|
|
590
659
|
|
|
591
|
-
|
|
592
|
-
|
|
660
|
+
- [Immutable-ext](https://github.com/DrBoolean/immutable-ext)
|
|
661
|
+
- Fantasyland extensions for immutablejs
|
|
593
662
|
|
|
594
|
-
[
|
|
663
|
+
- [Immutable-js-tools](https://github.com/madeinfree/immutable-js-tools)
|
|
664
|
+
- Util tools for immutable.js
|
|
595
665
|
|
|
596
|
-
|
|
597
|
-
|
|
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.
|
|
598
669
|
|
|
599
|
-
|
|
600
|
-
|
|
670
|
+
- [Immutable-Treeutils](https://github.com/lukasbuenger/immutable-treeutils)
|
|
671
|
+
- Functional tree traversal helpers for ImmutableJS data structures.
|
|
601
672
|
|
|
673
|
+
- [Irecord](https://github.com/ericelliott/irecord)
|
|
674
|
+
- An immutable store that exposes an RxJS observable. Great for React.
|
|
602
675
|
|
|
603
|
-
|
|
604
|
-
|
|
676
|
+
- [Mudash](https://github.com/brianneisler/mudash)
|
|
677
|
+
- Lodash wrapper providing Immutable.JS support.
|
|
605
678
|
|
|
606
|
-
|
|
679
|
+
- [React-Immutable-PropTypes](https://github.com/HurricaneJames/react-immutable-proptypes)
|
|
680
|
+
- PropType validators that work with Immutable.js.
|
|
607
681
|
|
|
682
|
+
- [Redux-Immutablejs](https://github.com/indexiatech/redux-immutablejs)
|
|
683
|
+
- Redux Immutable facilities.
|
|
608
684
|
|
|
609
|
-
|
|
610
|
-
|
|
685
|
+
- [Rxstate](https://github.com/yamalight/rxstate)
|
|
686
|
+
- Simple opinionated state management library based on RxJS and Immutable.js.
|
|
611
687
|
|
|
612
|
-
|
|
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)
|
|
613
691
|
|
|
614
|
-
|
|
692
|
+
Have an additional tool designed to work with Immutable.js?
|
|
693
|
+
Submit a PR to add it to this list in alphabetical order.
|
|
615
694
|
|
|
695
|
+
## Contributing
|
|
616
696
|
|
|
617
|
-
|
|
618
|
-
---------
|
|
697
|
+
Use [Github issues](https://github.com/immutable-js/immutable-js/issues) for requests.
|
|
619
698
|
|
|
620
|
-
|
|
699
|
+
We actively welcome pull requests, learn how to [contribute](https://github.com/immutable-js/immutable-js/blob/main/.github/CONTRIBUTING.md).
|
|
621
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/).
|
|
622
702
|
|
|
623
|
-
|
|
624
|
-
|
|
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
|
|
625
712
|
|
|
626
713
|
[Phil Bagwell](https://www.youtube.com/watch?v=K2NYwP90bNs), for his inspiration
|
|
627
714
|
and research in persistent data structures.
|
|
628
715
|
|
|
629
716
|
[Hugh Jackson](https://github.com/hughfdjackson/), for providing the npm package
|
|
630
717
|
name. If you're looking for his unsupported package, see [this repository](https://github.com/hughfdjackson/immutable).
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
License
|
|
634
|
-
-------
|
|
635
|
-
|
|
636
|
-
Immutable.js is [MIT-licensed](https://github.com/facebook/immutable-js/blob/master/LICENSE).
|