8000 Deploy d6352e474f8cb664570c69325502d9173ead7759 to NPM branch · datianyun/immutable-js@0f57ebe · GitHub
[go: up one dir, main page]

Skip to content

Commit 0f57ebe

Browse files
author
Travis CI
committed
Deploy d6352e4 to NPM branch
1 parent 4052ab8 commit 0f57ebe

File tree

1 file changed

+135
-63
lines changed

1 file changed

+135
-63
lines changed

README.md

Lines changed: 135 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -363,93 +363,100 @@ const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6))
363363
```
364364

365365

366-
Lazy Seq
367-
--------
366+
Equality treats Collections as Values
367+
-------------------------------------
368368

369-
`Seq` describes a lazy operation, allowing them to efficiently chain
370-
use of all the sequence methods (such as `map` and `filter`).
369+
Immutable.js collections are treated as pure data *values*. Two immutable
370+
collections are considered *value equal* (via `.equals()` or `is()`) if they
371+
represent the same collection of values. This differs from JavaScript's typical
372+
*reference equal* (via `===` or `==`) for Objects and Arrays which only
373+
determines if two variables represent references to the same object instance.
371374

372-
**Seq is immutable** — Once a Seq is created, it cannot be
373-
changed, appended to, rearranged or otherwise modified. Instead, any mutative
374-
method called on a Seq will return a new Seq.
375-
376-
**Seq is lazy** — Seq does as little work as necessary to respond to any
377-
method call.
378-
379-
For example, the following does not perform any work, because the resulting
380-
Seq is never used:
375+
Consider the example below where two identical `Map` instances are not
376+
*reference equal* but are *value equal*.
381377

378+
<!-- runkit:activate -->
382379
```js
383-
const { Seq } = require('immutable')
384-
const oddSquares = Seq([ 1, 2, 3, 4, 5, 6, 7, 8 ])
385-
.filter(x => x % 2)
386-
.map(x => x * x)
387-
```
388-
389-
Once the Seq is used, it performs only the work necessary. In this
390-
example, no intermediate arrays are ever created, filter is called three times,
391-
and map is only called once:
380+
// First consider:
381+
const obj1 = { a: 1, b: 2, c: 3 }
382+
const obj2 = { a: 1, b: 2, c: 3 }
383+
obj1 !== obj2 // two different instances are always not equal with ===
392384

393-
```js
394-
console.log(oddSquares.get(1)); // 9
385+
const { Map, is } = require('immutable')
386+
const map1 = Map({ a: 1, b: 2, c: 3 })
387+
const map2 = Map({ a: 1, b: 2, c: 3 })
388+
map1 !== map2 // two different instances are not reference-equal
389+
map1.equals(map2) // but are value-equal if they have the same values
390+
is(map1, map2) // alternatively can use the is() function
395391
```
396392

397-
Any collection can be converted to a lazy Seq with `.toSeq()`.
393+
Value equality allows Immutable.js collections to be used as keys in Maps or
394+
values in Sets, and retrieved with different but equivalent collections:
398395

399396
<!-- runkit:activate -->
400397
```js
401-
const { Map } = require('immutable')
402-
const seq = Map({ a: 1, b: 2, c: 3 }).toSeq()
398+
const { Map, Set } = require('immutable')
399+
const map1 = Map({ a: 1, b: 2, c: 3 })
400+
const map2 = Map({ a: 1, b: 2, c: 3 })
401+
const set = Set().add(map1)
402+
set.has(map2) // true because these are value-equal
403403
```
404404

405-
Seq allows for the efficient chaining of sequence operations, especially when
406-
converting to a different concrete type (such as to a JS object):
405+
Note: `is()` uses the same measure of equality as [Object.is][] for scalar
406+
strings and numbers, but uses value equality for Immutable collections,
407+
determining if both are immutable and all keys and values are equal
408+
using the same measure of equality.
407409

408-
```js
409-
seq.flip().map(key => key.toUpperCase()).flip().toObject();
410-
// { A: 1, B: 2, C: 3 }
411-
```
410+
[Object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
412411

413-
As well as expressing logic that would otherwise seem memory-limited:
412+
#### Performance tradeoffs
414413

415-
<!-- runkit:activate -->
416-
```js
417-
const { Range } = require('immutable')
418-
Range(1, Infinity)
419-
.skip(1000)
420-
.map(n => -n)
421-
.filter(n => n % 2 === 0)
422-
.take(2)
423-
.reduce((r, n) => r * n, 1);
424-
// 1006008
425-
```
426-
427-
Note: A Collection is always iterated in the same order, however that order may
428-
not always be well defined, as is the case for the `Map`.
414+
While value equality is useful in many circumstances, it has different
415+
performance characteristics than reference equality. Understanding these
416+
tradeoffs may help you decide which to use in each case, especially when used
417+
to memoize some operation.
429418

419+
When comparing two collections, value equality may require considering every
420+
item in each collection, on an `O(N)` time complexity. For large collections of
421+
values, this could become a costly operation. Though if the two are not equal
422+
and hardly similar, the inequality is determined very quickly. In contrast, when
423+
comparing two collections with reference equality, only the initial references
424+
to memory need to be compared which is not based on the size of the collections,
425+
which has an `O(1)` time complexity. Checking reference equality is always very
426+
fast, however just because two collections are not reference-equal does not rule
427+
out the possibility that they may be value-equal.
430428

431-
Equality treats Collections as Data
432-
-----------------------------------
429+
#### Return self on no-op optimization
433430

434-
Immutable.js provides equality which treats immutable data structures as pure
435-
data, performing a deep equality check if necessary.
431+
When possible, Immutable.js avoids creating new objects for updates where no
432+
change in *value* occurred, to allow for efficient *reference equality* checking
433+
to quickly determine if no change occurred.
436434

437435
<!-- runkit:activate -->
438436
```js
439-
const { Map, is } = require('immutable')
440-
const map1 = Map({ a: 1, b: 2, c: 3 })
441-
const map2 = Map({ a: 1, b: 2, c: 3 })
442-
assert.equal(map1 !== map2, true) // two different instances
443-
assert.equal(is(map1, map2), true) // have equivalent values
444-
assert.equal(map1.equals(map2), true) // alternatively use the equals method
437+
const { Map } = require('immutable')
438+
const originalMap = Map({ a: 1, b: 2, c: 3 })
439+
const updatedMap = originalMap.set('b', 2)
440+
updatedMap === originalMap // No-op .set() returned the original reference.
445441
```
446442

447-
`Immutable.is()` uses the same measure of equality as [Object.is][]
448-
including if both are immutable and all keys and values are equal
449-
using the same measure of equality.
450-
451-
[Object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
443+
However updates which do result in a change will return a new reference. Each
444+
of these operations occur independently, so two similar updates will not return
445+
the same reference:
452446

447+
<!-- runkit:activate -->
448+
```js
449+
const { Map } = require('immutable')
450+
const originalMap = Map({ a: 1, b: 2, c: 3 })
451+
const updatedMap = originalMap.set('b', 1000)
452+
// New instance, leaving the original immutable.
453+
updatedMap !== originalMap
454+
const anotherUpdatedMap = originalMap.set('b', 1000)
455+
// Despite both the results of the same operation, each created a new reference.
456+
anotherUpdatedMap !== updatedMap
457+
// However the two are value equal.
458+
anotherUpdatedMap.equals(updatedMap)
459+
```
453460

454461
Batching Mutations
455462
------------------
@@ -493,6 +500,71 @@ and `splice` will always return new immutable data-structures and never mutate
493500
a mutable collection.
494501

495502

503+
Lazy Seq
504+
--------
505+
506+
`Seq` describes a lazy operation, allowing them to efficiently chain
507+
use of all the sequence methods (such as `map` and `filter`).
508+
509+
**Seq is immutable** — Once a Seq is created, it cannot be
510+
changed, appended to, rearranged or otherwise modified. Instead, any mutative
511+
method called on a Seq will return a new Seq.
512+
513+
**Seq is lazy** — Seq does as little work as necessary to respond to any
514+
method call.
515+
516+
For example, the following does not perform any work, because the resulting
517+
Seq is never used:
518+
519+
```js
520+
const { Seq } = require('immutable')
521+
const oddSquares = Seq([ 1, 2, 3, 4, 5, 6, 7, 8 ])
522+
.filter(x => x % 2)
523+
.map(x => x * x)
524+
```
525+
526+
Once the Seq is used, it performs only the work necessary. In this
527+
example, no intermediate arrays are ever created, filter is called three times,
528+
and map is only called once:
529+
530+
```js
531+
console.log(oddSquares.get(1)); // 9
532+
```
533+
534+
Any collection can be converted to a lazy Seq with `.toSeq()`.
535+
536+
<!-- runkit:activate -->
537+
```js
538+
const { Map } = require('immutable')
539+
const seq = Map({ a: 1, b: 2, c: 3 }).toSeq()
540+
```
541+
542+
Seq allows for the efficient chaining of sequence operations, especially when
543+
converting to a different concrete type (such as to a JS object):
544+
545+
```js
546+
seq.flip().map(key => key.toUpperCase()).flip().toObject();
547+
// { A: 1, B: 2, C: 3 }
548+
```
549+
550+
As well as expressing logic that would otherwise seem memory-limited:
551+
552+
<!-- runkit:activate -->
553+
```js
554+
const { Range } = require('immutable')
555+
Range(1, Infinity)
556+
.skip(1000)
557+
.map(n => -n)
558+
.filter(n => n % 2 === 0)
559+
.take(2)
560+
.reduce((r, n) => r * n, 1);
561+
// 1006008
562+
```
563+
564+
Note: A Collection is always iterated in the same order, however that order may
565+
not always be well defined, as is the case for the `Map`.
566+
567+
496568
Documentation
497569
-------------
498570

0 commit comments

Comments
 (0)
0