Gathering detailed insights and metrics for seamless-immutable
Gathering detailed insights and metrics for seamless-immutable
Gathering detailed insights and metrics for seamless-immutable
Gathering detailed insights and metrics for seamless-immutable
Immutable data structures for JavaScript which are backwards-compatible with normal JS Arrays and Objects.
npm install seamless-immutable
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
5,370 Stars
509 Commits
195 Forks
59 Watching
5 Branches
41 Contributors
Updated on 27 Nov 2024
Minified
Minified + Gzipped
JavaScript (100%)
Cumulative downloads
Total Downloads
Last day
-9.1%
68,620
Compared to previous day
Last week
2.3%
401,867
Compared to previous week
Last month
8.1%
1,669,411
Compared to previous month
Last year
-16.3%
19,671,695
Compared to previous year
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.
1var array = Immutable(["totally", "immutable", {hammer: "Can’t Touch This"}]); 2 3array[1] = "I'm going to mutate you!" 4array[1] // "immutable" 5 6array[2].hammer = "hm, surely I can mutate this nested object..." 7array[2].hammer // "Can’t Touch This" 8 9for (var index in array) { console.log(array[index]); } 10// "totally" 11// "immutable" 12// { hammer: 'Can’t Touch This' } 13 14JSON.stringify(array) // '["totally","immutable",{"hammer":"Can’t Touch This"}]'
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+)
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.
In the development build, objects are frozen. (Note that Safari is relatively slow to iterate over frozen objects.) The development build also overrides unsupported methods (methods that ordinarily mutate the underlying data structure) to throw helpful exceptions.
The production (minified) build does neither of these, which significantly improves performance.
We generally recommend to use the "development" build that enforces immutability (and this is the default in Node.js). Only switch to the production build when you encounter performance problems. (See #50 for how to do that in Node or using a build tool - essentially do explicitely refer to the production build.)
By popular demand, functions, errors, dates, and React
components are treated as immutable even though technically they can be mutated.
(It turns out that trying to make these immutable leads to more bad things
than good.) If you call Immutable()
on any of these, be forewarned: they will
not actually be immutable!
seamless-immutable is tightly focused on the mechanics of turning existing JavaScript data structures into immutable variants. Additional packages are available to build on this capability and enable additional programming models:
Library | Description |
---|---|
Cursor | Compact Cursor Library built on top of the excellent seamless-immutable. Cursors can be used to manage transitions and manipulations of immutable structures in an application. |
Mergers | A collection of mergers for use with seamless-immutable. Also includes documentation about custom mergers, with examples, for writing your own. |
Immutable()
returns a backwards-compatible immutable representation of whatever you pass it, so feel free to pass it absolutely anything that can be serialized as JSON. (As is the case with JSON, objects containing circular references are not allowed. Functions are allowed, unlike in JSON, but they will not be touched.)
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 these important differences:
ImmutableError
.foo[5] = bar
) will not work. Browsers other than Internet Explorer will throw a TypeError
if use strict is enabled, and in all other cases it will fail silently.For example:
1Immutable([3, 1, 4]).sort() 2// This will throw an ImmutableError, because sort() is a mutating method. 3 4Immutable([1, 2, 3]).concat([10, 9, 8]).sort() 5// This will also throw ImmutableError, because an Immutable Array's methods 6// (including concat()) are guaranteed to return other immutable values. 7 8[1, 2, 3].concat(Immutable([6, 5, 4])).sort() 9// This will succeed, and will yield a sorted mutable array containing 10// [1, 2, 3, 4, 5, 6], because a vanilla array's concat() method has 11// no knowledge of Immutable. 12 13var obj = Immutable({all: "your base", are: {belong: "to them"}}); 14Immutable.merge(obj, {are: {belong: "to us"}}) 15// This will return the following: 16// Immutable({all: "your base", are: {belong: "to us"}})
Seamless-immutable supports both static and instance syntaxes:
1var Immutable = require("seamless-immutable").static; 2var obj = {}; 3 4Immutable.setIn(obj, ['key'], data)
1var Immutable = require("seamless-immutable"); 2var obj = {}; 3 4obj.setIn(['key'], data)
Although the later is shorter and is the current default, it can lead to collisions and some users may dislike polluting object properties when it comes to debugging. As such the first syntax is recommended, but both are supported.
If your linter cringes with the use of Immutable
without a preceding new
(e.g. ESLint's new-cap rule),
use Immutable.from
:
1Immutable.from([1, 2, 3]); 2// is functionally the same as calling: 3Immutable([1, 2, 3])
Like a regular Array, but immutable! You can construct these by passing
an array to Immutable()
:
1Immutable([1, 2, 3]) 2// An immutable array containing 1, 2, and 3.
Beyond the usual Array fare, the following methods have been added.
1var array = Immutable(["here", "we", "go"]); 2Immutable.flatMap(array, function(str) { 3 return [str, str, str]; 4}); 5// returns Immutable(["here", "here", "here", "we", "we", "we", "go", "go", "go"]) 6 7var array = Immutable(["drop the numbers!", 3, 2, 1, 0, null, undefined]); 8Immutable.flatMap(array, function(value) { 9 if (typeof value === "number") { 10 return []; 11 } else { 12 return value; 13 } 14}); 15// returns Immutable(["drop the numbers!", null, undefined])
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.
1var array = Immutable([1,2,3]); 2array.map(value => [value+2, value+4]); 3// returns Immutable([ [ 3, 5 ], [ 4, 6 ], [ 5, 7 ] ]) 4 5Immutable.flatMap(array, value => [value+2, value+4]); 6// returns Immutable([ 3, 5, 4, 6, 5, 7 ])
1var array = Immutable(["hey", "you"]); 2Immutable.asObject(array, function(str) { 3 return [str, str.toUpperCase()]; 4}); 5// returns Immutable({hey: "HEY", you: "YOU"})
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.
You can also call .asObject
without passing an iterator, in which case it will proceed assuming the Array
is already organized as desired.
1var array = Immutable(["hello", "world"]); 2var mutableArray = Immutable.asMutable(array); 3 4mutableArray.push("!!!"); 5 6mutableArray // ["hello", "world", "!!!"]
Returns a mutable copy of the array. For a deeply mutable copy, in which any instances of Immutable
contained in nested data structures within the array have been converted back to mutable data structures, call Immutable.asMutable(obj, {deep: true})
instead.
1var array = Immutable(["hello", "world"]); 2var mutableArray = ["hello", "world"]; 3 4Immutable.isImmutable(array) 5// returns true 6 7Immutable.isImmutable(mutableArray) 8// returns false
Returns whether an object is immutable or not.
In addition, Immutable Arrays also provide member functions for the set
, setIn
, update
, updateIn
, and getIn
functions (described below).
1var array = Immutable(["hello", "world"]); 2 3// Equivalent to Immutable.set(array, 1, "you"); 4var mutatedArray = array.set(1, "you"); 5 6mutatedArray // ["hello", "you"]
Like a regular Object, but immutable! You can construct these by passing an
object to Immutable()
.
1Immutable({foo: "bar"}) 2// An immutable object containing the key "foo" and the value "bar".
To construct an Immutable Object with a custom prototype, simply specify the
prototype in options
(while useful for preserving prototypes, please note
that custom mutator methods will not work as the object will be immutable):
1function Square(length) { this.length = length }; 2Square.prototype.area = function() { return Math.pow(this.length, 2) }; 3 4Immutable(new Square(2), {prototype: Square.prototype}).area(); 5// An immutable object, with prototype Square, 6// containing the key "length" and method `area()` returning 4
Beyond the usual Object fare, the following methods have been added.
Currently you can't construct Immutable from an object with circular references. To protect from ugly stack overflows, we provide a simple protection during development. We stop at a suspiciously deep stack level and show an error message.
If your objects are deep, but not circular, you can increase this level from default 64
. For example:
1Immutable(deepObject, null, 256);
This check is not performed in the production build.
1var obj = Immutable({status: "good", hypothesis: "plausible", errors: 0}); 2Immutable.merge(obj, {status: "funky", hypothesis: "confirmed"}); 3// returns Immutable({status: "funky", hypothesis: "confirmed", errors: 0}) 4 5var obj = Immutable({status: "bad", errors: 37}); 6Immutable.merge(obj, [ 7 {status: "funky", errors: 1}, {status: "groovy", errors: 2}, {status: "sweet"}]); 8// returns Immutable({status: "sweet", errors: 2}) 9// because passing an Array is shorthand for 10// invoking a separate merge for each object in turn.
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 in an Array in which case more merge
invocations will be performed using each provided object in turn.
A third argument can be provided to configure the merge. It should be an object with any of the following fields:
1{ 2 deep: true, // perform a deep merge 3 merger: yourCustomMerger // supply a custom merger 4}
You can find examples and documentation about custom mergers here.
1var obj1 = Immutable({a: {b: 'test'}, c: 'test'}); 2var obj2 = Immutable.replace(obj1, {a: {b: 'test'}}, {deep: true}); 3// returns Immutable({a: {b: 'test'}}); 4obj1 === obj2 5// returns false 6obj1.a === obj2.a 7// returns true because child .a objects were identical
Returns an Immutable Object containing the properties and values of the second object only. With deep merge, all child objects are checked for equality and the original immutable object is returned when possible.
A second argument can be provided to perform a deep merge: {deep: true}
.
1var obj = Immutable({type: "parrot", subtype: "Norwegian Blue", status: "alive"}); 2Immutable.set(obj, "status", "dead"); 3// returns Immutable({type: "parrot", subtype: "Norwegian Blue", status: "dead"})
Returns an Immutable Object with a single property set to the provided value. Basically a more straightforward way of saying
1var obj = Immutable({type: "parrot", subtype: "Norwegian Blue", status: "alive"}); 2Immutable.merge(obj, {status: "dead"});
(and more convenient with non-literal keys unless you have ES6 [computed_property_names]
).
An additional argument can be provided to perform a deep compare: {deep: true}
.
When called with an Immutable Array, the property parameter is the index to be changed:
1var array = Immutable(["hello", "world"]); 2var mutatedArray = Immutable.set(array, 1, "you"); 3 4mutatedArray // ["hello", "you"]
If the {deep: true}
parameter is provided when using an Immutable Array, the object at the provided index will be merged with the provided value using Immutable.merge()
.
Like set, but accepts a nested path to the property.
1var obj = Immutable({type: {main: "parrot", sub: "Norwegian Blue"}, status: "alive"}); 2Immutable.setIn(obj, ["type", "sub"], "Norwegian Ridgeback"); 3// returns Immutable({type: {main: "parrot", sub: "Norwegian Ridgeback"}, status: "alive"})
An additional argument can be provided to perform a deep compare: {deep: true}
.
When called with an Immutable Array, at least the first value in the path should be an index. This also works with nested arrays:
1var array = Immutable([["one fish", "two fish"], ["red fish", "blue fish"]]); 2var mutatedArray = Immutable.setIn(array, [1, 1], "green fish"); 3 4mutatedArray // [["one fish", "two fish"], ["red fish", "green fish"]]
Returns the value at the given path. A default value can be provided as a second argument.
1var obj = Immutable({type: {main: "parrot", subtype: "Norwegian Blue"}, status: "alive"}); 2Immutable.getIn(obj, ["type", "subtype"]); 3// returns "Norwegian Blue" 4Immutable.getIn(obj, ["type", "class"], "Aves"); 5// returns "Aves"
Returns an Immutable Object with a single property updated using the provided updater function.
1function inc (x) { return x + 1 } 2var obj = Immutable({foo: 1}); 3Immutable.update(obj, "foo", inc); 4// returns Immutable({foo: 2})
All additional arguments will be passed to the updater function.
1function add (x, y) { return x + y } 2var obj = Immutable({foo: 1}); 3Immutable.update(obj, "foo", add, 10); 4// returns Immutable({foo: 11})
Like update, but accepts a nested path to the property.
1function add (x, y) { return x + y } 2var obj = Immutable({foo: {bar: 1}}); 3Immutable.updateIn(obj, ["foo", "bar"], add, 10); 4// returns Immutable({foo: {bar: 11}})
1var obj = Immutable({the: "forests", will: "echo", with: "laughter"}); 2Immutable.without(obj, "with"); 3// returns Immutable({the: "forests", will: "echo"}) 4 5var obj = Immutable({the: "forests", will: "echo", with: "laughter"}); 6Immutable.without(obj, ["will", "with"]); 7// returns Immutable({the: "forests"}) 8 9var obj = Immutable({the: "forests", will: "echo", with: "laughter"}); 10Immutable.without(obj, "will", "with"); 11// returns Immutable({the: "forests"}) 12 13var obj = Immutable({the: "forests", will: "echo", with: "laughter"}); 14Immutable.without(obj, (value, key) => key === "the" || value === "echo"); 15// returns Immutable({with: "laughter"})
Returns an Immutable Object excluding the given keys or keys/values satisfying the given predicate from the existing object.
Multiple keys can be provided, either in an Array or as extra arguments.
1var obj = Immutable({when: "the", levee: "breaks"}); 2var mutableObject = Immutable.asMutable(obj); 3 4mutableObject.have = "no place to go"; 5 6mutableObject // {when: "the", levee: "breaks", have: "no place to go"}
Returns a mutable copy of the object. For a deeply mutable copy, in which any instances of Immutable
contained in nested data structures within the object have been converted back to mutable data structures, call Immutable.asMutable(obj, {deep: true})
instead.
Fixed bug with custom mergers treating all non-truthy values as undefined (#244).
Treat Blob
instances as immutable. Use Array.isArray
over instanceof
.
Treat Error
instances as immutable.
Fix .npmignore
Add getIn
and assumption that Promises are immutable.
Add Immutable.static
as the preferred API. Default to development build in webpack.
Adds optional deep compare for .set
, .setIn
and .replace
Adds static alternatives to methods, e.g. Immutable.setIn
Fixes bug with deep merge() on an array argument.
Fixes bug with setting a new object on an existing leaf array.
Fixes bug where on some systems arrays are treated as plain objects.
without
now handles numeric keys the same way as string keys.
Alias Immutable.from()
to Immutable()
for linters.
React components are now considered immutable.
Add cycle detection.
Add update
and updateIn
.
Immutable(Object.create(null))
now works as expected.
Add predicate support to without()
Fix missing dev/prod builds for 5.0.0
In development build, freeze Dates and ban mutating methods. (Note: dev and prod builds were mistakenly not generated for this, so to get this functionality in those builds, use 5.0.1)
Make setIn
more null safe.
Adds set
and setIn
Now when you require("seamless-immutable")
, you get the development build by default.
main
now points to src/seamless-immutable.js
so you can more easily build with envify
yourself.
Add support for optional prototyping.
Calling .asMutable({deep: true}) on an Immutable data structure with a nested Date no longer throws an exception.
Arrays with nonstandard prototypes no longer throw exceptions when passed to Immutable
.
Custom mergers now check for reference equality and abort early if there is no more work needed, allowing improved performance.
Fixes a bug where indices passed into iterators for flatMap and asObject were strings instead of numbers.
Fixes an IE and Firefox bug related to cloning Dates while preserving their prototypes.
Dates now retain their prototypes, the same way Arrays do.
Adds a minified production build with no freezing or defensive unsupported methods, for a ~2x performance boost.
Adds optional merger
function to #merge
.
Bugfix: #merge
with {deep: true}
no longer attempts (unsuccessfully) to deeply merge arrays as though they were regular objects.
Minor documentation typo fix.
Breaking API change: #merge
now takes exactly one or exactly two arguments. The second is optional and allows specifying deep: true
.
Don't bother returning a new value from #merge
if no changes would result.
Make error message for invalid #asObject
less fancy, resulting in a performance improvement.
Adds #asMutable
Initial stable release
Run npm install -g grunt-cli
, npm install
and then grunt
to build and test it.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 existing vulnerabilities detected
Reason
Found 7/16 approved changesets -- score normalized to 4
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More