GithubHelp home page GithubHelp logo

jeffmo / immutable-js Goto Github PK

View Code? Open in Web Editor NEW

This project forked from immutable-js/immutable-js

0.0 3.0 0.0 19.14 MB

Immutable persistent data collections for Javascript which increase efficiency and simplicity.

Home Page: http://facebook.github.io/immutable-js/

License: Other

JavaScript 71.93% TypeScript 28.02% Shell 0.05%

immutable-js's Introduction

Immutable collections for JavaScript

Build Status

Immutable data cannot be changed once created, leading to much simpler application development, no defensive copying, and enabling advanced memoization and change detection techniques with simple logic. Persistent data presents a mutative API which does not update the data in-place, but instead always yields new updated data.

Immutable provides Persistent Immutable List, Stack, Map, OrderedMap, Set, OrderedSet and Record. They are highly efficient on modern JavaScript VMs by using structural sharing via hash maps tries and vector tries as popularized by Clojure and Scala, minimizing the need to copy or cache data.

Immutable also provides a lazy Seq, allowing efficient chaining of collection methods like map and filter without creating intermediate representations. Create some Seq with Range and Repeat.

Getting started

Install immutable using npm.

npm install immutable

Then require it into any module.

var Immutable = require('immutable');
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50

Browser

To use immutable from a browser, download dist/immutable.min.js or use a CDN such as CDNJS or jsDelivr.

Then, add it as a script tag to your page:

<script src="immutable.min.js"></script>
<script>
    var map1 = Immutable.Map({a:1, b:2, c:3});
    var map2 = map1.set('b', 50);
    map1.get('b'); // 2
    map2.get('b'); // 50
</script>

Or use an AMD loader (such as RequireJS):

require(['./immutable.min.js'], function (Immutable) {
    var map1 = Immutable.Map({a:1, b:2, c:3});
    var map2 = map1.set('b', 50);
    map1.get('b'); // 2
    map2.get('b'); // 50
});

If you're using browserify, the immutable npm module also works from the browser.

TypeScript

Use these Immutable collections and sequences as you would use native collections in your TypeScript programs while still taking advantage of type generics, error detection, and auto-complete in your IDE.

Just add a reference with a relative path to the type declarations at the top of your file.

///<reference path='./node_modules/immutable/dist/Immutable.d.ts'/>
import Immutable = require('immutable');
var map1: Immutable.Map<string, number>;
map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 20);
map1.get('b'); // 2
map2.get('b'); // 50

The case for Immutability

Much of what makes application development difficult is tracking mutation and maintaining state. Developing with immutable data encourages you to think differently about how data flows through your application.

Subscribing to data events throughout your application, by using Object.observe, or any other mechanism, creates a huge overhead of book-keeping which can hurt performance, sometimes dramatically, and creates opportunities for areas of your application to get out of sync with each other due to easy to make programmer error. Since immutable data never changes, subscribing to changes throughout the model is a dead-end and new data can only ever be passed from above.

This model of data flow aligns well with the architecture of React and especially well with an application designed using the ideas of Flux.

When data is passed from above rather than being subscribed to, and you're only interested in doing work when something has changed, you can use equality. Immutable always returns itself when a mutation results in an identical collection, allowing for using === equality to determine if something has changed.

var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 2);
assert(map1 === map2);
var map3 = map1.set('b', 50);
assert(map1 !== map3);

If an object is immutable, it can be "copied" simply by making another reference to it instead of copying the entire object. Because a reference is much smaller than the object itself, this results in memory savings and a potential boost in execution speed for programs which rely on copies (such as an undo-stack).

var map1 = Immutable.Map({a:1, b:2, c:3});
var clone = map1;

JavaScript-first API

While immutable is inspired by Clojure, Scala, Haskell and other functional programming environments, it's designed to bring these powerful concepts to JavaScript, and therefore has an Object-Oriented API that closely mirrors that of ES6 Array, Map, and Set.

The difference for the immutable collections is that methods which would mutate the collection, like push, set, unshift or splice instead return a new immutable collection. Methods which return new arrays like slice or concat instead return new immutable collections.

var list1 = Immutable.List.of(1, 2);
var list2 = list1.push(3, 4, 5);
var list3 = list2.unshift(0);
var list4 = list1.concat(list2, list3);
assert(list1.size === 2);
assert(list2.size === 5);
assert(list3.size === 6);
assert(list4.size === 13);
assert(list4.get(0) === 1);

Almost all of the methods on Array will be found in similar form on Immutable.List, those of Map found on Immutable.Map, and those of Set found on Immutable.Set, including collection operations like forEach() and map().

var alpha = Immutable.Map({a:1, b:2, c:3, d:4});
alpha.map((v, k) => k.toUpperCase()).join();
// 'A,B,C,D'

Accepts raw JavaScript objects.

Designed to inter-operate with your existing JavaScript, immutable accepts plain JavaScript Arrays and Objects anywhere a method expects an Iterable with no performance penalty.

var map1 = Immutable.Map({a:1, b:2, c:3, d:4});
var map2 = Immutable.Map({c:10, a:20, t:30});
var obj = {d:100, o:200, g:300};
var map3 = map1.merge(map2, obj);
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }

This is possible because immutable can treat any JavaScript Array or Object as an Iterable. You can take advantage of this in order to get sophisticated collection methods on JavaScript Objects, which otherwise have a very sparse native API. Because Seq evaluates lazily and does not cache intermediate results, these operations can be extremely efficient.

var myObject = {a:1,b:2,c:3};
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 }

Converts back to raw JavaScript objects.

All immutable Iterables can be converted to plain JavaScript Arrays and Objects shallowly with toArray() and toObject() or deeply with toJS(). All Immutable Iterables also implement toJSON() allowing them to be passed to JSON.stringify directly.

var deep = Immutable.Map({ a: 1, b: 2, c: Immutable.List.of(3, 4, 5) });
deep.toObject() // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
deep.toArray() // [ 1, 2, List [ 3, 4, 5 ] ]
deep.toJS() // { a: 1, b: 2, c: [ 3, 4, 5 ] }
JSON.stringify(deep) // '{"a":1,"b":2,"c":[3,4,5]}'

Embraces ES6

Immutable takes advantage of features added to JavaScript in ES6, the latest standard version of ECMAScript (JavaScript), including Iterators, Arrow Functions, Classes, and Modules. It's also inspired by the Map and Set collections added to ES6. The library is "transpiled" to ES3 in order to support all modern browsers.

All examples are presented in ES6. To run in all browsers, they need to be translated to ES3.

// ES6
foo.map(x => x * x);
// ES3
foo.map(function (x) { return x * x; });

Nested Structures

The collections in immutable are intended to be nested, allowing for deep trees of data, similar to JSON.

var nested = Immutable.fromJS({a:{b:{c:[3,4,5]}}});
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }

A few power-tools allow for reading and operating on nested data. The most useful are mergeDeep, getIn, setIn, and updateIn, found on List, Map and OrderedMap.

var nested2 = nested.mergeDeep({a:{b:{d:6}}});
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
nested2.getIn(['a', 'b', 'd']); // 6

var nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }

var nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }

Lazy Seq

Seq describes a lazy operation, allowing them to efficiently chain use of all the Iterable methods (such as map and filter).

Seq is immutable — Once a Seq is created, it cannot be changed, appended to, rearranged or otherwise modified. Instead, any mutative method called on a Seq will return a new Seq.

Seq is lazy — Seq does as little work as necessary to respond to any method call.

For example, the following does not perform any work, because the resulting Seq is never used:

var oddSquares = Immutable.Seq.of(1,2,3,4,5,6,7,8)
  .filter(x => x % 2).map(x => x * x);

Once the Seq is used, it performs only the work necessary. In this example, no intermediate arrays are ever created, filter is called three times, and map is only called twice:

console.log(oddSquares.get(1)); // 9

Any collection can be converted to a lazy Seq with .toSeq().

var seq = Immutable.Map({a:1, b:1, c:1}).toSeq();

Seq allow for the efficient chaining of sequence operations, especially when converting to a different concrete type (such as to a JS object):

seq.flip().map(key => key.toUpperCase()).flip().toObject();
// Map { A: 1, B: 1, C: 1 }

As well as expressing logic that would otherwise seem memory-limited:

Immutable.Range(1, Infinity)
  .skip(1000)
  .map(n => -n)
  .filter(n => n % 2 === 0)
  .take(2)
  .reduce((r, n) => r * n, 1);
// 1006008

Note: An iterable is always iterated in the same order, however that order may not always be well defined, as is the case for the Map.

Equality treats Collections as Data

Immutable provides equality which treats immutable data structures as pure data, performing a deep equality check if necessary.

var map1 = Immutable.Map({a:1, b:1, c:1});
var map2 = Immutable.Map({a:1, b:1, c:1});
assert(map1 !== map2);
assert(Immutable.is(map1, map2) === true);

Immutable.is() uses the same measure of equality as Object.is including if both are immutable and all keys and values are equal using the same measure of equality.

Batching Mutations

If a tree falls in the woods, does it make a sound?

If a pure function mutates some local data in order to produce an immutable return value, is that ok?

— Rich Hickey, Clojure

Applying a mutation to create a new immutable object results in some overhead, which can add up to a performance penalty. If you need to apply a series of mutations locally before returning, Immutable gives you the ability to create a temporary mutable (transient) copy of a collection and apply a batch of mutations in a performant manner by using withMutations. In fact, this is exactly how Immutable applies complex mutations itself.

As an example, building list2 results in the creation of 1, not 3, new immutable Lists.

var list1 = Immutable.List.of(1,2,3);
var list2 = list1.withMutations(function (list) {
  list.push(4).push(5).push(6);
});
assert(list1.size === 3);
assert(list2.size === 6);

Note: immutable also provides asMutable and asImmutable, but only encourages their use when withMutations will not suffice. Use caution to not return a mutable copy, which could result in undesired behavior.

Documentation

Read the docs and eat your vegetables.

Docs are automatically generated from Immutable.d.ts. Please contribute!

Also, don't miss the Wiki which contains articles on specific topics. Can't find something? Open an issue.

Contribution

Use Github issues for requests.

We actively welcome pull requests, learn how to contribute.

Changelog

Changes are tracked as Github releases.

Thanks

Hugh Jackson, for providing the npm package name. If you're looking for his unsupported package, see v1.4.1.

Phil Bagwell, for his inspiration and research in persistent data structures.

License

Immutable is BSD-licensed. We also provide an additional patent grant.

immutable-js's People

Contributors

blittle avatar bobbuehler avatar briandipalma avatar carlsverre avatar cybrown avatar davidtimms avatar delapouite avatar dsissitka-private avatar etripier avatar gabelevi avatar ihodes avatar incrediblesound avatar istarkov avatar jmperez avatar joshk avatar kyleamathews avatar leebyron avatar leejarvis avatar leoasis avatar lilmoeymoey avatar luigy avatar markdalgleish avatar mosch avatar pluma avatar sdknjg8zxq avatar sophiebits avatar tolmasky avatar vrana avatar wolffiex avatar zertosh avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.