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 +350 -181
- package/contrib/cursor/README.md +12 -2
- package/contrib/cursor/__tests__/Cursor.ts.skip +9 -14
- package/contrib/cursor/index.d.ts +244 -247
- package/contrib/cursor/index.js +19 -0
- package/dist/immutable-nonambient.d.ts +4122 -1318
- package/dist/immutable.d.ts +4122 -1318
- package/dist/immutable.es.js +5818 -0
- package/dist/immutable.js +4293 -3406
- package/dist/immutable.js.flow +1396 -392
- package/dist/immutable.min.js +32 -28
- package/package.json +78 -60
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Immutable collections for JavaScript
|
|
2
2
|
====================================
|
|
3
3
|
|
|
4
|
-
[](https://travis-ci.org/facebook/immutable-js)
|
|
4
|
+
[](https://travis-ci.org/facebook/immutable-js) [](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
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
map1.
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
```
|
|
80
|
+
```js
|
|
73
81
|
require(['./immutable.min.js'], function (Immutable) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
|
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 [
|
|
205
|
+
of [ES2015][] [Array][], [Map][], and [Set][].
|
|
169
206
|
|
|
170
|
-
[
|
|
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
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
assert(
|
|
188
|
-
assert(
|
|
189
|
-
assert(
|
|
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
|
-
|
|
198
|
-
|
|
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
|
-
###
|
|
244
|
+
### Convert from raw JavaScript objects and arrays.
|
|
204
245
|
|
|
205
|
-
Designed to inter-operate with your existing JavaScript,
|
|
206
|
-
accepts plain JavaScript Arrays and Objects anywhere a method expects
|
|
207
|
-
`
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
218
|
-
as
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
obj
|
|
237
|
-
obj
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
map
|
|
241
|
-
map.get(1);
|
|
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
|
|
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
|
|
254
|
-
`JSON.stringify` directly.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
deep
|
|
261
|
-
|
|
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
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
|
273
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
//
|
|
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
|
|
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
|
-
|
|
295
|
-
|
|
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
|
-
|
|
304
|
-
|
|
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
|
-
|
|
309
|
-
nested2.getIn(['a', 'b', 'd']); // 6
|
|
380
|
+
console.log(nested2.getIn([ 'a', 'b', 'd' ])); // 6
|
|
310
381
|
|
|
311
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
400
|
+
Consider the example below where two identical `Map` instances are not
|
|
401
|
+
*reference equal* but are *value equal*.
|
|
343
402
|
|
|
344
|
-
|
|
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
|
-
|
|
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
|
-
|
|
349
|
-
|
|
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
|
-
|
|
352
|
-
|
|
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
|
-
|
|
435
|
+
[Object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
|
355
436
|
|
|
356
|
-
|
|
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
|
-
|
|
365
|
-
|
|
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
|
-
|
|
369
|
-
-----------------------------------
|
|
454
|
+
#### Return self on no-op optimization
|
|
370
455
|
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
|
415
|
-
assert(list2.size
|
|
513
|
+
assert.equal(list1.size, 3);
|
|
514
|
+
assert.equal(list2.size, 6);
|
|
416
515
|
```
|
|
417
516
|
|
|
418
|
-
Note:
|
|
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
|
|
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](
|
|
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
|