Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

README.md 16 KiB

il y a 3 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. Immutable collections for JavaScript
  2. ====================================
  3. [![Build Status](https://travis-ci.org/facebook/immutable-js.svg)](https://travis-ci.org/facebook/immutable-js)
  4. [Immutable][] data cannot be changed once created, leading to much simpler
  5. application development, no defensive copying, and enabling advanced memoization
  6. and change detection techniques with simple logic. [Persistent][] data presents
  7. a mutative API which does not update the data in-place, but instead always
  8. yields new updated data.
  9. `Immutable` provides Persistent Immutable `List`, `Stack`, `Map`, `OrderedMap`,
  10. `Set`, `OrderedSet` and `Record`. They are highly efficient on modern JavaScript
  11. VMs by using structural sharing via [hash maps tries][] and
  12. [vector tries][] as popularized by Clojure and Scala,
  13. minimizing the need to copy or cache data.
  14. `Immutable` also provides a lazy `Seq`, allowing efficient
  15. chaining of collection methods like `map` and `filter` without creating
  16. intermediate representations. Create some `Seq` with `Range` and `Repeat`.
  17. [Persistent]: http://en.wikipedia.org/wiki/Persistent_data_structure
  18. [Immutable]: http://en.wikipedia.org/wiki/Immutable_object
  19. [hash maps tries]: http://en.wikipedia.org/wiki/Hash_array_mapped_trie
  20. [vector tries]: http://hypirion.com/musings/understanding-persistent-vector-pt-1
  21. Getting started
  22. ---------------
  23. Install `immutable` using npm.
  24. ```shell
  25. npm install immutable
  26. ```
  27. Then require it into any module.
  28. ```javascript
  29. var Immutable = require('immutable');
  30. var map1 = Immutable.Map({a:1, b:2, c:3});
  31. var map2 = map1.set('b', 50);
  32. map1.get('b'); // 2
  33. map2.get('b'); // 50
  34. ```
  35. ### Browser
  36. To use `immutable` from a browser, download [dist/immutable.min.js](./dist/immutable.min.js)
  37. or use a CDN such as [CDNJS](https://cdnjs.com/libraries/immutable)
  38. or [jsDelivr](http://www.jsdelivr.com/#!immutable.js).
  39. Then, add it as a script tag to your page:
  40. ```html
  41. <script src="immutable.min.js"></script>
  42. <script>
  43. var map1 = Immutable.Map({a:1, b:2, c:3});
  44. var map2 = map1.set('b', 50);
  45. map1.get('b'); // 2
  46. map2.get('b'); // 50
  47. </script>
  48. ```
  49. Or use an AMD loader (such as [RequireJS](http://requirejs.org/)):
  50. ```javascript
  51. require(['./immutable.min.js'], function (Immutable) {
  52. var map1 = Immutable.Map({a:1, b:2, c:3});
  53. var map2 = map1.set('b', 50);
  54. map1.get('b'); // 2
  55. map2.get('b'); // 50
  56. });
  57. ```
  58. If you're using [browserify](http://browserify.org/), the `immutable` npm module
  59. also works from the browser.
  60. ### TypeScript
  61. Use these Immutable collections and sequences as you would use native
  62. collections in your [TypeScript](http://typescriptlang.org) programs while still taking
  63. advantage of type generics, error detection, and auto-complete in your IDE.
  64. Just add a reference with a relative path to the type declarations at the top
  65. of your file.
  66. ```javascript
  67. ///<reference path='./node_modules/immutable/dist/immutable.d.ts'/>
  68. import Immutable = require('immutable');
  69. var map1: Immutable.Map<string, number>;
  70. map1 = Immutable.Map({a:1, b:2, c:3});
  71. var map2 = map1.set('b', 50);
  72. map1.get('b'); // 2
  73. map2.get('b'); // 50
  74. ```
  75. The case for Immutability
  76. -------------------------
  77. Much of what makes application development difficult is tracking mutation and
  78. maintaining state. Developing with immutable data encourages you to think
  79. differently about how data flows through your application.
  80. Subscribing to data events throughout your application, by using
  81. `Object.observe`, or any other mechanism, creates a huge overhead of
  82. book-keeping which can hurt performance, sometimes dramatically, and creates
  83. opportunities for areas of your application to get out of sync with each other
  84. due to easy to make programmer error. Since immutable data never changes,
  85. subscribing to changes throughout the model is a dead-end and new data can only
  86. ever be passed from above.
  87. This model of data flow aligns well with the architecture of [React][]
  88. and especially well with an application designed using the ideas of [Flux][].
  89. When data is passed from above rather than being subscribed to, and you're only
  90. interested in doing work when something has changed, you can use equality.
  91. Immutable collections should be treated as *values* rather than *objects*. While
  92. objects represents some thing which could change over time, a value represents
  93. the state of that thing at a particular instance of time. This principle is most
  94. important to understanding the appropriate use of immutable data. In order to
  95. treat Immutable.js collections as values, it's important to use the
  96. `Immutable.is()` function or `.equals()` method to determine value equality
  97. instead of the `===` operator which determines object reference identity.
  98. ```javascript
  99. var map1 = Immutable.Map({a:1, b:2, c:3});
  100. var map2 = map1.set('b', 2);
  101. assert(map1.equals(map2) === true);
  102. var map3 = map1.set('b', 50);
  103. assert(map1.equals(map3) === false);
  104. ```
  105. Note: As a performance optimization `Immutable` attempts to return the existing
  106. collection when an operation would result in an identical collection, allowing
  107. for using `===` reference equality to determine if something definitely has not
  108. changed. This can be extremely useful when used within memoization function
  109. which would prefer to re-run the function if a deeper equality check could
  110. potentially be more costly. The `===` equality check is also used internally by
  111. `Immutable.is` and `.equals()` as a performance optimization.
  112. If an object is immutable, it can be "copied" simply by making another reference
  113. to it instead of copying the entire object. Because a reference is much smaller
  114. than the object itself, this results in memory savings and a potential boost in
  115. execution speed for programs which rely on copies (such as an undo-stack).
  116. ```javascript
  117. var map1 = Immutable.Map({a:1, b:2, c:3});
  118. var clone = map1;
  119. ```
  120. [React]: http://facebook.github.io/react/
  121. [Flux]: http://facebook.github.io/flux/docs/overview.html
  122. JavaScript-first API
  123. --------------------
  124. While `immutable` is inspired by Clojure, Scala, Haskell and other functional
  125. programming environments, it's designed to bring these powerful concepts to
  126. JavaScript, and therefore has an Object-Oriented API that closely mirrors that
  127. of [ES6][] [Array][], [Map][], and [Set][].
  128. [ES6]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla
  129. [Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
  130. [Map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
  131. [Set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
  132. The difference for the immutable collections is that methods which would mutate
  133. the collection, like `push`, `set`, `unshift` or `splice` instead return a new
  134. immutable collection. Methods which return new arrays like `slice` or `concat`
  135. instead return new immutable collections.
  136. ```javascript
  137. var list1 = Immutable.List.of(1, 2);
  138. var list2 = list1.push(3, 4, 5);
  139. var list3 = list2.unshift(0);
  140. var list4 = list1.concat(list2, list3);
  141. assert(list1.size === 2);
  142. assert(list2.size === 5);
  143. assert(list3.size === 6);
  144. assert(list4.size === 13);
  145. assert(list4.get(0) === 1);
  146. ```
  147. Almost all of the methods on [Array][] will be found in similar form on
  148. `Immutable.List`, those of [Map][] found on `Immutable.Map`, and those of [Set][]
  149. found on `Immutable.Set`, including collection operations like `forEach()`
  150. and `map()`.
  151. ```javascript
  152. var alpha = Immutable.Map({a:1, b:2, c:3, d:4});
  153. alpha.map((v, k) => k.toUpperCase()).join();
  154. // 'A,B,C,D'
  155. ```
  156. ### Accepts raw JavaScript objects.
  157. Designed to inter-operate with your existing JavaScript, `immutable`
  158. accepts plain JavaScript Arrays and Objects anywhere a method expects an
  159. `Iterable` with no performance penalty.
  160. ```javascript
  161. var map1 = Immutable.Map({a:1, b:2, c:3, d:4});
  162. var map2 = Immutable.Map({c:10, a:20, t:30});
  163. var obj = {d:100, o:200, g:300};
  164. var map3 = map1.merge(map2, obj);
  165. // Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
  166. ```
  167. This is possible because `immutable` can treat any JavaScript Array or Object
  168. as an Iterable. You can take advantage of this in order to get sophisticated
  169. collection methods on JavaScript Objects, which otherwise have a very sparse
  170. native API. Because Seq evaluates lazily and does not cache intermediate
  171. results, these operations can be extremely efficient.
  172. ```javascript
  173. var myObject = {a:1,b:2,c:3};
  174. Immutable.Seq(myObject).map(x => x * x).toObject();
  175. // { a: 1, b: 4, c: 9 }
  176. ```
  177. Keep in mind, when using JS objects to construct Immutable Maps, that
  178. JavaScript Object properties are always strings, even if written in a quote-less
  179. shorthand, while Immutable Maps accept keys of any type.
  180. ```js
  181. var obj = { 1: "one" };
  182. Object.keys(obj); // [ "1" ]
  183. obj["1"]; // "one"
  184. obj[1]; // "one"
  185. var map = Immutable.fromJS(obj);
  186. map.get("1"); // "one"
  187. map.get(1); // undefined
  188. ```
  189. Property access for JavaScript Objects first converts the key to a string, but
  190. since Immutable Map keys can be of any type the argument to `get()` is
  191. not altered.
  192. ### Converts back to raw JavaScript objects.
  193. All `immutable` Iterables can be converted to plain JavaScript Arrays and
  194. Objects shallowly with `toArray()` and `toObject()` or deeply with `toJS()`.
  195. All Immutable Iterables also implement `toJSON()` allowing them to be passed to
  196. `JSON.stringify` directly.
  197. ```javascript
  198. var deep = Immutable.Map({ a: 1, b: 2, c: Immutable.List.of(3, 4, 5) });
  199. deep.toObject() // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
  200. deep.toArray() // [ 1, 2, List [ 3, 4, 5 ] ]
  201. deep.toJS() // { a: 1, b: 2, c: [ 3, 4, 5 ] }
  202. JSON.stringify(deep) // '{"a":1,"b":2,"c":[3,4,5]}'
  203. ```
  204. ### Embraces ES6
  205. `Immutable` takes advantage of features added to JavaScript in [ES6][],
  206. the latest standard version of ECMAScript (JavaScript), including [Iterators][],
  207. [Arrow Functions][], [Classes][], and [Modules][]. It's also inspired by the
  208. [Map][] and [Set][] collections added to ES6. The library is "transpiled" to ES3
  209. in order to support all modern browsers.
  210. All examples are presented in ES6. To run in all browsers, they need to be
  211. translated to ES3.
  212. ```js
  213. // ES6
  214. foo.map(x => x * x);
  215. // ES3
  216. foo.map(function (x) { return x * x; });
  217. ```
  218. [Iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol
  219. [Arrow Functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
  220. [Classes]: http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes
  221. [Modules]: http://www.2ality.com/2014/09/es6-modules-final.html
  222. Nested Structures
  223. -----------------
  224. The collections in `immutable` are intended to be nested, allowing for deep
  225. trees of data, similar to JSON.
  226. ```javascript
  227. var nested = Immutable.fromJS({a:{b:{c:[3,4,5]}}});
  228. // Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }
  229. ```
  230. A few power-tools allow for reading and operating on nested data. The
  231. most useful are `mergeDeep`, `getIn`, `setIn`, and `updateIn`, found on `List`,
  232. `Map` and `OrderedMap`.
  233. ```javascript
  234. var nested2 = nested.mergeDeep({a:{b:{d:6}}});
  235. // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
  236. ```
  237. ```javascript
  238. nested2.getIn(['a', 'b', 'd']); // 6
  239. var nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1);
  240. // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
  241. var nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6));
  242. // Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
  243. ```
  244. Lazy Seq
  245. --------
  246. `Seq` describes a lazy operation, allowing them to efficiently chain
  247. use of all the Iterable methods (such as `map` and `filter`).
  248. **Seq is immutable** — Once a Seq is created, it cannot be
  249. changed, appended to, rearranged or otherwise modified. Instead, any mutative
  250. method called on a Seq will return a new Seq.
  251. **Seq is lazy** — Seq does as little work as necessary to respond to any
  252. method call.
  253. For example, the following does not perform any work, because the resulting
  254. Seq is never used:
  255. var oddSquares = Immutable.Seq.of(1,2,3,4,5,6,7,8)
  256. .filter(x => x % 2).map(x => x * x);
  257. Once the Seq is used, it performs only the work necessary. In this
  258. example, no intermediate arrays are ever created, filter is called three times,
  259. and map is only called twice:
  260. console.log(oddSquares.get(1)); // 9
  261. Any collection can be converted to a lazy Seq with `.toSeq()`.
  262. var seq = Immutable.Map({a:1, b:1, c:1}).toSeq();
  263. Seq allow for the efficient chaining of sequence operations, especially when
  264. converting to a different concrete type (such as to a JS object):
  265. seq.flip().map(key => key.toUpperCase()).flip().toObject();
  266. // Map { A: 1, B: 1, C: 1 }
  267. As well as expressing logic that would otherwise seem memory-limited:
  268. Immutable.Range(1, Infinity)
  269. .skip(1000)
  270. .map(n => -n)
  271. .filter(n => n % 2 === 0)
  272. .take(2)
  273. .reduce((r, n) => r * n, 1);
  274. // 1006008
  275. Note: An iterable is always iterated in the same order, however that order may
  276. not always be well defined, as is the case for the `Map`.
  277. Equality treats Collections as Data
  278. -----------------------------------
  279. `Immutable` provides equality which treats immutable data structures as pure
  280. data, performing a deep equality check if necessary.
  281. ```javascript
  282. var map1 = Immutable.Map({a:1, b:1, c:1});
  283. var map2 = Immutable.Map({a:1, b:1, c:1});
  284. assert(map1 !== map2); // two different instances
  285. assert(Immutable.is(map1, map2)); // have equivalent values
  286. assert(map1.equals(map2)); // alternatively use the equals method
  287. ```
  288. `Immutable.is()` uses the same measure of equality as [Object.is][]
  289. including if both are immutable and all keys and values are equal
  290. using the same measure of equality.
  291. [Object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
  292. Batching Mutations
  293. ------------------
  294. > If a tree falls in the woods, does it make a sound?
  295. >
  296. > If a pure function mutates some local data in order to produce an immutable
  297. > return value, is that ok?
  298. >
  299. > — Rich Hickey, Clojure
  300. Applying a mutation to create a new immutable object results in some overhead,
  301. which can add up to a minor performance penalty. If you need to apply a series
  302. of mutations locally before returning, `Immutable` gives you the ability to
  303. create a temporary mutable (transient) copy of a collection and apply a batch of
  304. mutations in a performant manner by using `withMutations`. In fact, this is
  305. exactly how `Immutable` applies complex mutations itself.
  306. As an example, building `list2` results in the creation of 1, not 3, new
  307. immutable Lists.
  308. ```javascript
  309. var list1 = Immutable.List.of(1,2,3);
  310. var list2 = list1.withMutations(function (list) {
  311. list.push(4).push(5).push(6);
  312. });
  313. assert(list1.size === 3);
  314. assert(list2.size === 6);
  315. ```
  316. Note: `immutable` also provides `asMutable` and `asImmutable`, but only
  317. encourages their use when `withMutations` will not suffice. Use caution to not
  318. return a mutable copy, which could result in undesired behavior.
  319. *Important!*: Only a select few methods can be used in `withMutations` including
  320. `set`, `push` and `pop`. These methods can be applied directly against a
  321. persistent data-structure where other methods like `map`, `filter`, `sort`,
  322. and `splice` will always return new immutable data-structures and never mutate
  323. a mutable collection.
  324. Documentation
  325. -------------
  326. [Read the docs](http://facebook.github.io/immutable-js/docs/) and eat your vegetables.
  327. Docs are automatically generated from [Immutable.d.ts](https://github.com/facebook/immutable-js/blob/master/type-definitions/Immutable.d.ts).
  328. Please contribute!
  329. Also, don't miss the [Wiki](https://github.com/facebook/immutable-js/wiki) which
  330. contains articles on specific topics. Can't find something? Open an [issue](https://github.com/facebook/immutable-js/issues).
  331. Contribution
  332. ------------
  333. Use [Github issues](https://github.com/facebook/immutable-js/issues) for requests.
  334. We actively welcome pull requests, learn how to [contribute](./CONTRIBUTING.md).
  335. Changelog
  336. ---------
  337. Changes are tracked as [Github releases](https://github.com/facebook/immutable-js/releases).
  338. Thanks
  339. ------
  340. [Phil Bagwell](https://www.youtube.com/watch?v=K2NYwP90bNs), for his inspiration
  341. and research in persistent data structures.
  342. [Hugh Jackson](https://github.com/hughfdjackson/), for providing the npm package
  343. name. If you're looking for his unsupported package, see [v1.4.1](https://www.npmjs.org/package/immutable/1.4.1).
  344. License
  345. -------
  346. `Immutable` is [BSD-licensed](./LICENSE). We also provide an additional [patent grant](./PATENTS).