This project is no longer actively supported. If anyone is interested in becoming the new maintainer, don't hesitate to contact me (hughfdjackson@googlemail.com).
The go-to immutable library is https://github.com/facebook/immutable-js.
Effecient immutable collections in javascript.
Using immutable objects can make code easier to reason about, allowing programmers to geniunely create sections of their programs that operate on a 'data-in/data-out' basis.
This style of code is easy to test, and use in a mix-and-match style.
npm install immutable
Download build/immutable.js, and include it as a script tag.
Download build/immutable.js, and require it in:
require(['libs/immutable'], function(immutable){
// ... assuming immutable is in libs/immutable.js, now it's ready to use
})
Immutable has two types of collection: objects and arrays. Like regular JavaScript Objects and Arrays, both act as key:value stores (using strings as the keys).
var person = im.object({ name: 'joe bloggs', age: 34 })
var numbers = im.array([1, 2, 3, 4, 5])
var emptyObj = im.object()
var person = emptyObj.assoc({ name: 'joe bloggs', age: 34 })
var personWithSports = person.assoc('sport', 'golf')
var emptyArr = im.array()
var numbers = emptyArr.assoc([1, 2, 3, 4, 5])
var upTo6 = numbers.assoc(5, 6)
var person = im.object({ name: 'joe bloggs', age: 34 })
person.get('age') //= 34
var numbers = im.array([1, 2, 3, 4, 5])
numbers.get(0) //= 1
var person = im.object({ name: 'joe bloggs', age: 34 })
person.has('name') //= true
person.has('discography') //= false
Create a collection like this one, but without a particular property:
var person = im.object({ name: 'joe bloggs', age: 34 })
var personShyAboutAge = person.dissoc('age')
personShyAboutAge.has('age') //= false
var numbers = im.array([1, 2, 3, 4, 5])
var upTo4 = numbers.dissoc(4) // dissocs the 4th key
numbers.has(4) //= true
upTo4.has(4) //= false
Create a regular JavaScript object from an immutable one:
var person = im.object({ name: 'joe bloggs', age: 34 })
person.mutable() //= { name: 'joe bloggs', age: 34 }
The .toJSON
alias allows immutable objects to be serialised seamlessly with regular objects:
var favouritePeople = {
joe: im.object({ name: 'joe bloggs', age: 34, sports: im.array(['golf', 'carting']) })
}
JSON.stringify(favouritePeople) // = '{ "joe": { "name": "joe bloggs", "age": 34, "sports": ["golf", "carting"] } }'
Collections can be checked for equality:
var person1 = im.object({ name: 'joe bloggs', age: 34 })
var person2 = im.object({ name: 'joe bloggs', age: 34 })
var person3 = im.object({ name: 'joe bloggs', age: 34, sport: 'golf' })
person1.equal(person2) //= true
person3.equal(person2) //= false
Collections are considered equal when:
Immutable objects and arrays can be iterated over almost identically, except that:
All iterator methods (unless mentioned) will pass the value, the key, and the original immutable object to their callback functions.
var inc = function(a){ return a + 1 }
var coordinates = im.object({ x: 1, y: 1 })
coordinates.map(inc).mutable() //= { x: 2, y: 3 }
var numbers = im.array([1, 2, 3, 4, 5])
numbers.map(inc).mutable() //= [2, 3, 4, 5, 6]
var log = console.log.bind(console)
var person = im.object({ name: 'joe bloggs', age: 34 })
person.map(log)
// *log output*
// 'joe bloggs' 'name' person
// 34 'age' person
var isNum = function(a){ return typeof a === 'number' }
var person = im.object({ name: 'joe bloggs', age: 34 })
person.filter(isNum).mutable() //= { age: 34 }
var alphaNumber = im.array(['a', 1, 'b', 2, 'c', 3])
alphaNumber.filter(isNum).mutable() //= [1, 2, 3]
var isNum = function(a){ return typeof a === 'number' }
im.object({ name: 'joe bloggs', age: 34 }).every(isNum) //= false
im.object({ x: 1, y: 2 }).every(isNum) //= true
im.array(['a', 1, 'b', 2, 'c', 3]).every(isNum) //= false
im.array([1, 2, 3]).every(isNum) //= true
var isNum = function(a){ return typeof a === 'number' }
im.object({ name: 'joe bloggs', sport: 'golf' }).some(isNum) //= false
im.object({ name: 'joe bloggs', age: 34 }).some(isNum) //= true
im.array(['a', 'b', 'c']).some(isNum) //= false
im.array(['a', 1, 'b', 2, 'c', 3]).every(isNum) //= true
var flip = function(coll, val, key){
return coll.assoc(key, val)
}
var coords = im.object({ x: '1', y: '2', z: '3' })
var flippedCoords = coords.reduce(flip, im.object())
flippedCoords.mutable() //= { 1: 'x', 2: 'y', 3: 'z' }
var cat = function(a, b){ return a + b }
var letters = im.array(['a', 'b', 'c'])
letters.reduce(cat) //= 'abc'
Since arrays are ordered collections, they have some methods of their own, that only make sense in an ordered context:
var cat = function(a, b){ return a + b }
var letters = im.array(['a', 'b', 'c'])
letters.reduceRight(cat) //= 'cba'
var numbersTo3 = im.array([1, 2, 3])
var numbersTo4 = numbersTo3.push(4)
numbersTo4.mutable() //= [1, 2, 3, 4]
var mixed = im.array([1, 2, 3, im.object({ x: 3 }), { x: 3 }])
mixed.indexOf('a') //= -1 -- 'a' not in array
mixed.indexOf({ x: 3 }) //= -1 -- mutable objects are compared by reference
mixed.indexOf(im.object({ x: 3 })) //= 3 -- immutable objects are compared by value
mixed.indexOf(3) //= 2 -- primitives are compared by value
A predicate that returns true if the object is an immutable one, such as produced by this library.
im.isImmutableCollection(im.array([1, 2, 3])) //= true
im.isImmutableCollection(Object.freeze({})) //= false - you couldn't assoc/dissoc/get/set on it