What is seamless-immutable?
The seamless-immutable npm package provides a way to create and work with deeply immutable data structures in JavaScript. It ensures that objects and arrays cannot be modified after they are created, which helps in maintaining predictable state and avoiding side effects in applications.
What are seamless-immutable's main functionalities?
Creating Immutable Objects
This feature allows you to create immutable objects. Once created, the object cannot be modified.
const Immutable = require('seamless-immutable');
const obj = Immutable({ name: 'John', age: 30 });
console.log(obj); // Output: { name: 'John', age: 30 }
Creating Immutable Arrays
This feature allows you to create immutable arrays. Once created, the array cannot be modified.
const Immutable = require('seamless-immutable');
const arr = Immutable([1, 2, 3]);
console.log(arr); // Output: [1, 2, 3]
Merging Immutable Objects
This feature allows you to merge immutable objects, creating a new immutable object with the merged properties.
const Immutable = require('seamless-immutable');
const obj1 = Immutable({ name: 'John', age: 30 });
const obj2 = obj1.merge({ age: 31 });
console.log(obj2); // Output: { name: 'John', age: 31 }
Updating Immutable Arrays
This feature allows you to perform operations on immutable arrays, resulting in a new immutable array.
const Immutable = require('seamless-immutable');
const arr = Immutable([1, 2, 3]);
const newArr = arr.map(x => x * 2);
console.log(newArr); // Output: [2, 4, 6]
Other packages similar to seamless-immutable
immutable
The 'immutable' package provides persistent immutable data structures including List, Stack, Map, OrderedMap, Set, and OrderedSet. It offers more complex data structures and methods compared to seamless-immutable, but can be more complex to use.
immer
The 'immer' package allows you to work with immutable state by using a 'draft' state that you can modify directly. It then produces the next immutable state based on the changes. It is simpler to use for complex state updates compared to seamless-immutable.
mori
The 'mori' package provides a set of Clojure-inspired immutable data structures and functions for JavaScript. It is more functional programming-oriented and offers a different approach compared to seamless-immutable.
seamless-immutable
Immutable JS data structures which are backwards-compatible with normal Arrays and Objects.
Use them in for
loops, pass them to functions expecting vanilla JavaScript data structures, etc.
var array = Immutable(["totally", "immutable", {hammer: "Can’t Touch This"}]);
array[1] = "I'm going to mutate you!"
array[1]
array[2].hammer = "hm, surely I can mutate this nested object..."
array[2].hammer
for (var index in array) { console.log(array[index]); }
JSON.stringify(array)
This level of backwards compatibility requires ECMAScript 5 features like Object.defineProperty and Object.freeze to exist and work correctly, which limits the browsers that can use this library to the ones shown in the test results below. (tl;dr IE9+)
Performance
Whenever you deeply clone large nested objects, it should typically go much faster with Immutable
data structures. This is because the library reuses the existing nested objects rather than instantiating new ones.
Note that these objects are frozen, and Safari is relatively slow to iterate over frozen objects. If this makes a noticeable difference in your use case, you can monkey patch Object.freeze
to be the identity function before using Immutable
, but be aware that this carries the drawback of re-enabling property reassignment like array[2] = "new value"
.
API Overview
Immutable()
returns a backwards-compatible immutable representation of whatever you pass it, so feel free to pass it absolutely anything.
Since numbers, strings, undefined
, and null
are all immutable to begin with, the only unusual things it returns are Immutable Arrays and Immutable Objects. These have the same ES5 methods you’re used to seeing on them, but with three important differences:
- All the methods that would normally mutate the data structures instead throw
ImmutableError
. - All the methods that return a relevant value now return an immutable equivalent of that value.
- A few additional methods have been added for convenience.
For example:
Immutable([3, 1, 4]).sort()
Immutable([1, 2, 3]).concat([10, 9, 8]).sort()
[1, 2, 3].concat(Immutable([6, 5, 4])).sort()
Immutable({all: "your base", are: {belong: "to them"}}).merge({are: {belong: "to us"}})
Immutable Array
Like a regular Array, but immutable! You can construct these either by passing
an array to Immutable()
, or simply by passing it multiple arguments:
Immutable([1, 2, 3])
Immutable(1, 2, 3)
Immutable(1)
Beyond the usual Array fare, the following methods have been added.
flatMap
Immutable(["here", "we", "go"]).flatMap(function(str) {
return [str, str, str];
});
Immutable(["drop the numbers!", 3, 2, 1, 0, null, undefined]).flatMap(function(value) {
if (typeof value === "number") {
return [];
} else {
return value;
}
});
Effectively performs a map over the elements in the array, except that whenever the provided
iterator function returns an Array, that Array's elements are each added to the final result.
asObject
Immutable(["hey", "you"]).asObject(function(str) {
return [str, str.toUpperCase()];
});
Effectively performs a map over the elements in the array, expecting that the iterator function
will return an array of two elements - the first representing a key, the other
a value. Then returns an Immutable Object constructed of those keys and values.
Immutable Object
Like a regular Object, but immutable! You can construct these by passing an
object to Immutable()
.
Immutable({foo: "bar"})
Beyond the usual Object fare, the following methods have been added.
merge
Immutable({status: "good", hypothesis: "plausible", errors: 0}).merge({status: "funky", hypothesis: "confirmed"})
Immutable({status: "bad", errors: 37}).merge([
{status: "funky", errors: 1}, {status: "groovy", errors: 2}, {status: "sweet"}])
Returns an Immutable Object containing the properties and values of both
this object and the provided object, prioritizing the provided object's
values whenever the same key is present in both objects.
Multiple objects can be provided, either in an Array or as extra arguments,
in which case more merge
invocations will be performed using each
provided object in turn.
without
Immutable({the: "forests", will: "echo", with: "laughter"}).without("with")
Immutable({the: "forests", will: "echo", with: "laughter"}).without(["will", "with"])
Immutable({the: "forests", will: "echo", with: "laughter"}).without("will", "with")
Returns an Immutable Object excluding the given keys from the existing object.
Multiple keys can be provided, either in an Array or as extra arguments.