Mutable object
In JavaScript, objects are reference-type data. The advantage is that when objects are frequently modified, they are modified based on the original object and do not need to be recreated. This can effectively utilize memory and will not cause waste of memory space. This characteristic of objects can be called Mutable, which means "mutable" in Chinese.
For Mutable objects, its flexibility and change may sometimes become its disadvantages. The more flexible and changeable the data is, the harder it is to control. For an object with a complex structure, the data is accidentally modified inadvertently. If the object is used in multiple scopes, it is difficult to foresee whether and when the data will change.
var obj = { /* An object with a complex structure*/ };doSomething(obj);// After the above function line is finished, is obj still the original obj at this time?To address this problem, a conventional solution can copy a new object by deep copying the object and then modifying it on the new object. This can ensure the controllability of the data, but frequent copying will cause a lot of waste of memory space.
var obj = { /* An object with a complex structure*/ };// copy creates a new obj2// But the copy operation will waste memory space var obj2 = deepClone(obj);doSomething(obj2);// After the above function is finished, regardless of whether obj2 changes, obj will definitely be the original objImmutable object
In order to better solve the above problems, the Immutable object appears, which is "immutable" literally translated into Chinese. Each time an Immutable object is modified, a new immutable object is created. Operation on the new object will not affect the data of the original object. This special object is not the new functional feature of JavaScript, but a set of solutions provided by the industry to solve this problem. Some excellent open source libraries have emerged, the most famous of which is Facebook's Lee Byron's open source immutable.js. Of course, Immutable's solution is not original, but comes from Clojure and Scala.
Performance comparison between Mutable and Immutable
The inefficient operation of Mutable objects is mainly reflected in replication and comparison, and the Immutable object solves these two inefficient pain points.
The deep copy operation of ordinary Mutable objects will copy the entire data. The Immutable object will not copy the entire data when modifying the data, but will transfer the parent-child relationship between the changed node and the unchanged node to a new node, similar to the structure of a linked list. From the perspective of "copy", the minimization of replication is achieved, and the unchanged parts are shared. Mutable is "full" when copying, while Immutable is "incremental", which determines the high or low usage rate of memory space.
And based on the feature that each time an Immutable object is modified, a new Immutable object will be created. This can save the modified state of the data into a set of snapshots, which is also quite convenient.
Let’s talk about the comparison operation. For Mutable objects, if you want to compare whether the two objects are equal, you must traverse each node of the object for comparison. For objects with complex structures, their efficiency is definitely not much higher. For Immutable objects, immutable.js provides an API that directly determines whether the "values" of two Immutable objects are equal.
var map1 = Immutable.Map({a:1, b:1, c:1});var map2 = Immutable.Map({a:1, b:1, c:1});assert(map1 !== map2); // Different Immutable instances, the reference address assert(Immutable.is(map1, map2)); // The values of map1 and map2 are equal, and the values assert(map1.equals(map2)); // The functions of Immutable.is are the sameIn actual development applications, performance is not always the most critical and important. For ordinary JavaScript projects, the controllability of data brought about by the characteristics of Immutable is more advantageous than performance. For Mutable objects, it is suitable for use in a closed scope, while Immutable objects are suitable for use when data needs to be passed across multiple scopes.
The difference between Mutable and Immutable
immutable.js provides a variety of Imutable data structures: including List Stack Map OrderedMap Set OrderedSet Record, which roughly correspond to the native Mutable data structure.
I won't explain the usage of each data structure here, but mainly talk about the difference between the use of Immutable objects and Mutable objects.
Native Mutable objects are very convenient for "reading" and "writing".
var mutableObj = {};// Write data mutableObj.foo = 'bar';// Read data console.log(mutableObj.foo);The Immutable object needs to "read" and "write" the data through set and get.
var immutableObj1 = Immutable.Map();// Write data var immutableObj2 = immutableObj1.set('foo', 'bar');// Read data console.log(immutableObj2.get('foo')); // => 'bar'In order to illustrate the use of the set method, the example above created an empty object at the beginning, and in fact, the initial value can be passed during instantiation.
var immutableObj = Immutable.Map({'foo', 'bar'});For data with deeper levels, the access interface provided by immutable.js is very convenient.
var immutableObj1 = Immutable.fromJS({ a: { b: 'c' }, d: [1, 2, 3]});// Read deep data console.log(immutableObj1.getIn(['a', 'b'])); // => 'c'console.log(immutableObj1.getIn(['a', 'b'])); // => 2// Modify deep data var immutableObj2 = immutableObj1.setIn(['a', 'b'], 'd');console.log(immutableObj2.getIn(['a', 'b'])); // => 'd'If it is a native Mutable object, an undefined error may be reported when accessing a deep level of data in a chain, while an Immutable object will not report an error when encountering this situation, and the return is undefined.
When debugging, if you want to view the internal structure of an Immutable object, it is recommended to use toJSON() to convert it to a normal Mutable object first.