Reprinted fromImmutable.js
Immutable.js
Handling JavaScript complex objects: deep copy, Immutable & Immer
This article is just a brief introduction to Immutable. We will continue to share the practical application of Immutable.
immutable.jpeg
What is Immutable Data?
Immutable data encourages pure functions (data-in, data-out) and lends itself to much simpler application development and enabling techniques from functional programming such as lazy evaluation.
— Official document description
Immutable Data is Data that, once created, cannot be changed. Any modification or addition or deletion of an Immutable object returns a new Immutable object. Immutable is a Persistent Data Structure, which ensures that old Data can be used to create new Data without changing it. And to avoid the performance cost of deepCopy copying all nodes once, Immutable uses Structural Sharing, where if a node in the object tree changes, only that node and its affected parent are modified, and the other nodes are shared. Watch the animation below:
Structure of Shared
Immutable has advantages and disadvantages
advantages
1. Reduce the complexity of Mutable
Shared mutable state is the root of all evil. A simple example is reference assignment in JS:
var obj = { a: 1 }; var copy_obj = obj; copy_obj.a = 2; console.log(obj.a); / / 2Copy the code
Reference assignment can save memory, but mutable state can become a nightmare when the application is complex. It is common to use shallowCopy or deepCopy to avoid modification, but this can cause CPU and memory consumption, but Immulate is a good solution to these problems.
2. Save memory space
As mentioned above, Immutable. Js uses this method to reuse as much memory as possible, and even objects previously used can be reused. Objects that are not referenced are garbage collected.
import { Map } from'immutable';
let a = Map({
select: 'users',
filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people');
a === b; // false
a.get('filter') === b.get('filter'); // true
Copy the code
Above, A and B share unchanged filter nodes.
3. Undo/Redo, Copy/Paste,
Because the data is different each time, it’s easy to develop undo redo by simply storing the data in an array and pulling it out wherever you want to go.
4. Embrace functional programming
Immutable (persistent data structures) is itself a concept in functional programming. Functional programming is concerned with the mapping of data, imperative programming is concerned with the steps to solve the problem, and pure functional programming is more suitable for front-end development than object-oriented programming. Because as long as the inputs are consistent, the outputs must be consistent, developing components is easier to debug and assemble.
disadvantages
Aside from the cost of learning and the additional resource files introduced, let’s take a look at some of the frustrations.
1. Easy to mix with native objects
The mainly Immutable API is designed to be similar to native objects and is easy to confuse operations. For example, the Map and List operations:
// Immutableconstmap = Map({ a: 1, b: 2 }); Constlist = List ([1, 2, 3]); // native jsconst obj = {a: 1, b: 2}; Const 'arry = [1, 2, 3]; // Compare console.log(map.get('a')); console.log(list.get(0)); console.log(obj.a); console.log(arry[0]);Copy the code
Immutable. Introduction of js
It took Facebook engineer Lee Byron three years to build and came out at the same time as React, but wasn’t included in the React toolkit by default (React provides a simplified Helper). It internally implements a complete set of Persistent Data Structure, as well as many easy-to-use Data types. Like Collection, List, Map, Set, Record, Seq. There are very comprehensive map, filter, groupBy, reduce ‘ ‘find function operation methods. Also, the API is as similar to Object or Array as possible.
immutablejs-getters-and-setters-everywhere.jpg
Several data types of Immutable
- List: An ordered set of indexes, similar to an Array in JavaScript.
- Map: An unordered set of indexes, similar to JavaScript objects.
- OrderedMap: an OrderedMap, sorted by the set() of the data.
- Set: A Set with no duplicate values.
- OrderedSet: an OrderedSet, sorted according to the add of data.
- Stack: Ordered collection, which can be added and deleted using unshift() and shift().
- Record: A class that generates an instance of Record. Object is similar to JavaScript Object, but only accepts a specific string as key, with a default value.
- Seq: sequence, but may not be supported by specific data structures.
- Collection: is the base class for building all data structures and cannot be built directly.
The most commonly used data types are lists and maps, so I’ll focus on the apis for those two data types here.
A common API for Immutable. Js
fromJS()
Function: To convert JS data to Immutable data
FromJS (value, Converter)
Summary: Value is the data to convert, converter is the operation to do. The second parameter is optional. By default, arrays are converted to List and objects are converted to Map
Code implementation:
const obj = Immutable.fromJS({a:'123',b:'234'},function (key, value, path) {
console.log(key, value, path)
return isIndexed(value) ? value.toList() : value.toOrderedMap())
})
Copy the code
toJS()
Function: To convert an Immutable data to JS data
Usage: value. ToJS ()
is()
Function: Compares two objects
Usage: is (map1, map2)
HashCode and valueOf are the same value as long as the hashcodes of two objects are equal. This method is used to improve performance and avoid deep iterating
Code implementation:
import { Map, is } from'immutable'const map1 = Map({ a: 1, b: 1, c: 1 })
const map2 = Map({ a: 1, b: 1, c: 1 })
map1 === map2 //falseObject.is(map1, map2) // false
is(map1, map2) // true
Copy the code
The List () and Map ()
Creates a new List/Map object
Usage:
//List Immutable.List(); // Empty List Immutable.List([1, 2]); //Map Immutable.Map(); // Empty Map Immutable.Map({a: '1', b: '2'});Copy the code
List. IsList () and Map. IsMap ()
Function: Check whether a data structure is of type List/Map
Usage:
List.isList([]); // false
List.isList(List()); // trueMap.isMap({}) // falseMap.isMap(Map()) // true
Copy the code
size
Action: property to get the length of List/Map, equivalent to immutableData.count ();
The get (), getIn ()
Gets data from a data structure
Immutabledata.get (0); Immutabledata.get ('a'); // Get data from a nested array immutableData.getin ([1, 2]); Immutabledata. getIn(['a', 'b']);Copy the code
From the (), hasIn ()
Function: Checks whether a key exists
Usage:
Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). From the (' 0 '); / / true Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). From the (' 0 '); / / true Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). HasIn ([3, 'b']) / / trueCopy the code
includes()
Function: Check whether a value exists
Usage:
Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). Includes (2); / / true Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). Includes (' 2 '); //false does not contain character 2 Immutable. FromJS ([1,2,3,{a:4,b:5}]). / / false Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). Includes ({5} a: 4, b:) / / false Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). Includes (Immutable) fromJS ({5} a: 4, b:)) / / trueCopy the code
The first () and last ()
Function: Gets the first or last element, or returns undefined
Code:
Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). The first () / / 1 Immutable. FromJS ([1, 2, 3, 5} {a: 4, b:]). The last () / / {5} a: 4, b: Immutable.fromJS({a:1,b:2,c:{d:3,e:4}}).first() //1 Immutable.fromJS({a:1,b:2,c:{d:3,e:4}}).first() //{d:3,e:4}Copy the code
Data modification
Note: An Immutable data type is an Immutable data type by which a value is assigned to a new data.
Set the set ()
Function: Set the key and index values of the first layer
Usage:
const originalList = List([ 0 ]);
// List [ 0 ]
originalList.set(1, 1);
// List [ 0, 1 ]
originalList.set(0, 'overwritten');
// List [ "overwritten" ]
originalList.set(2, 2);
// List [ 0, undefined, 2 ]List().set(50000, 'value').size;
// 50001const originalMap = Map()
const newerMap = originalMap.set('key', 'value')
const newestMap = newerMap.set('key', 'newer value')
originalMap
// Map {}
newerMap
// Map { "key": "value" }
newestMap
// Map { "key": "newer value" }
Copy the code
When used, set index to number to value. When Map is used, the key value is set to value.
When the number passed in the List is negative, the size+index value is set to value. For example, if the number passed in is -1, the size-1 value is set to value. If the number value passed in exceeds the length of the List, the List is automatically completed as the value of the number passed in, and the number is set to value. [,,,] : void exists in the List. If there is no value in the List, undefined.
setIn()
Function: Sets the value of an attribute in a deep structure
Usage:
const originalMap = Map({ subObject: Map({ subKey: 'subvalue', subSubObject: Map({ subSubKey: 'subSubValue' }) }) }) const newMap = originalMap.setIn(['subObject', 'subKey'], 'ha ha! ') // Map {// "subObject": Map {// "subKey": "ha ha!" ,// "subSubObject": Map { "subSubKey": "subSubValue" }// }// }const newerMap = originalMap.setIn( ['subObject', 'subSubObject', 'subSubKey'], 'ha ha ha! ' ) // Map {// "subObject": Map {// "subKey": "subvalue",// "subSubObject": Map { "subSubKey": "ha ha ha!" } / / / /}}Copy the code
The usage is the same as set(), except that the first argument is an array representing the location of the property to be set
Delete the delete
Function: Deletes attributes in a layer 1 structure
Usage:
// List
List([ 0, 1, 2, 3, 4 ]).delete(0);
// List [ 1, 2, 3, 4 ]// Mapconst originalMap = Map({
key: 'value',
otherKey: 'other value'
})
// Map { "key": "value", "otherKey": "other value" }
originalMap.delete('otherKey')
// Map { "key": "value" }
Copy the code
deleteIn()
Used to delete deep data, see setIn for usage
DeleteAll () (Map only, List not)
Function: Deletes multiple keys from a Map
Usage: deleteAll(keys: Iterable): this
Code examples:
const names = Map({ a: "Aaron", b: "Barry", c: "Connor" })
names.deleteAll([ 'a', 'c' ])
// Map { "b": "Barry" }
Copy the code
Update the update ()
Function: To update an attribute in an object. You can perform related operations on the original data
Usage:
////Listconstlist = List([ 'a', 'b', 'c' ])
const result = list.update(2, val => val.toUpperCase())
///Mapconst aMap = Map({ key: 'value' })
const newMap = aMap.update('key', value => value + value)
Copy the code
updateIn()
For usage, see setIn
Remove the clear ()
Action: Clears all data
Usage: clear(): this
Code examples:
Map({ key: 'value'}).clear() //MapList([1, 2, 3, 4]).clear() Like push, pop, Shift, unshift, insert.Copy the code
push()
Insert an element at the end of the List
pop()
Delete an element at the end of the List
unshift
Insert an element at the head of the List
shift
Delete an element at the head of the List
insert
Insert element at index of List
Code implementation:
List([ 0, 1, 2, 3, 4 ]).insert(6, 5)
//List [ 0, 1, 2, 3, 4, 5 ]List([ 1, 2, 3, 4 ]).push(5)
// List [ 1, 2, 3, 4, 5 ]List([ 1, 2, 3, 4 ]).pop()
// List[ 1, 2, 3 ]List([ 2, 3, 4]).unshift(1);
// List [ 1, 2, 3, 4 ]List([ 0, 1, 2, 3, 4 ]).shift();
// List [ 1, 2, 3, 4 ]
Copy the code
There’s also a special way to set the length of a List, setSize()
List([]).setSize(2).toJS() //[undefined,undefined]
Copy the code
About the merge
merge
Functions: shallow merge, compare the new data with the old data, add the attributes that do not exist in the old data directly, and overwrite the existing attributes in the new data
mergrWith
Function: custom shallow merge, you can set the value of some attributes
mergeIn
Function: Shallow merge of deep data
mergeDeep
Function: Deep merge. The attributes existing in the new and old data are the data after the merge of the new and old data
mergeDeepIn
Function: Deep merge deep data
mergrDeepWith
Function: Custom deep merge, you can set the value of some properties
Merge merge merge merge merge Merge Merge Merge Merge Merge Merge Merge Merge Merge
const Map1 = Immutable.fromJS({a:111,b:222,c:{d:333,e:444}});
const Map2 = Immutable.fromJS({a:111,b:222,c:{e:444,f:555}});
const Map3 = Map1.merge(Map2);
//Map {a:111,b:222,c:{e:444,f:555}}const Map4 = Map1.mergeDeep(Map2);
//Map {a:111,b:222,c:{d:333,e:444,f:555}}const Map5 = Map1.mergeWith((oldData,newData,key)=>{
if(key === 'a'){
return666;
}else{
return newData
}
},Map2);
//Map {a:666,b:222,c:{e:444,f:555}}
Copy the code
Sequence algorithm
concat()
Function: Concatenation of objects, used in the same way as concat() in js arrays, returns a new object.
Const List = list1.concat(list2)
map()
Returns a new object by iterating over the entire object, performing operations on the Map/List elements.
Usage:
Map({a:1,b:2}).map(val=>10*val)
//Map{a:10,b:20}
Copy the code
MapKey ()
Returns a new object by iterating over the entire object, operating on the key of the Map element.
Usage:
Map({a:1,b:2}).mapKey(val=>val+'l')
//Map{al:10,bl:20}
Copy the code
Map unique mapEntries()
Returns a new object by iterating over the entire object, operating on both the key and the value of the Map element. Map () of Map can also do this.
Usage:
Map({a:1,b:2}).map((key,val)=>{
return [key+'l',val*10]
})
//Map{al:10,bl:20}
Copy the code
Filter filter
Function: Returns a new object containing all elements that meet the filter criteria
Usage:
Map({a:1,b:2}).filter((key,val)=>{
return val == 2
})
//Map{b:2}
Copy the code
There is also a filterNot() method, which is the opposite.
Inversion of reverse
Function: Reverses the data structure
Code examples:
Immutable.fromJS([1, 2, 3, 4, 5]).reverse(); / / the List,4,3,2,1 [5] Immutable. FromJS ({a: 1, b: {2, c: d: 3}, e: 4}). The recerse (); //Map {e:4,b:{c:2,d:3},a:1}Copy the code
Sort sort & sortBy
Function: Sorts data structures
Code examples:
/ / / the List Immutable. FromJS (,3,5,2,6,1 [4]). The sort () / / the List [6] Immutable. FromJS (,3,5,2,6,1 [4]). Sort ((a, b) = > {the if (a < b) { return-1; } if (a > b) { return1; } if (a === b) { return0; }}) / / the List [6] Immutable. FromJS ([{a: 3}, {a: 2}, {a: 4}, {a: 1}]). The sortBy ((val, index, obj) = > {return val. Get (' a ') },(a,b)=>{ if (a < b) { return-1; } if (a > b) { return1; } if (a === b) { return0; } }) //List [ {a:3}, {a:2}, {a:4}, {a:1} ]//Map Immutable.fromJS( {b:1, a: 3, c: 2, d:5} ).sort() //Map {b: 1, c: 2, a: 3, d: 5} Immutable.fromJS( {b:1, a: 3, c: 2, d:5} ).sort((a,b)=>{ if (a < b) { return-1; } if (a > b) { return1; } if (a === b) { return0; } }) //Map {b: 1, c: 2, a: 3, d: 5} Immutable.fromJS( {b:1, a: 3, c: 2, d:5} ).sortBy((value, key, obj)=> { return value }) //Map {b: 1, c: 2, a: 3, d: 5}Copy the code
Grouping groupBy
Function: Group data
const listOfMaps = List([
Map({ v: 0 }),
Map({ v: 1 }),
Map({ v: 1 }),
Map({ v: 0 }),
Map({ v: 2 })
])
const groupsOfMaps = listOfMaps.groupBy(x => x.get('v'))
// Map {// 0: List [ Map{ "v": 0 }, Map { "v": 0 } ],// 1: List [ Map{ "v": 1 }, Map { "v": 1 } ],// 2: List [ Map{ "v": 2 } ],// }
Copy the code
To find the data
IndexOf () and lastIndexOf Map do not exist
Returns the index of the first or last value, or -1
Usage:
Immutable. FromJS ([1, 2, 3, 4]) indexof (3) / / 2 Immutable. FromJS ([1, 2, 3, 4]). LastIndexof (3) / / 2Copy the code
FindIndex () and findLastIndex() Map do not have this method
Function: Find the index value of an element that meets the requirement
Usage:
Immutable.fromjs ([1,2,3,4]).findindex ((value,index,array)=>{return value%2 === 0; }) // 1 immutable.fromjs ([1,2,3,4]).findLastIndex((value,index,array)=>{return index%2 === 0; }) / / 3Copy the code
The find (), findLast ()
Finds the value of an element that meets the condition
Usage:
FromJS ([1,2,3,4]). Find ((value,index,array)=>{return value%2 === 0; }) // 2 immutable.fromjs ([1,2,3,4]).findlast ((value,index,array)=>{return value%2 === 0; }) / / 4Copy the code
FindKey (), findLastKey ()
Finds the key of an element that meets the criteria
Usage:
Immutable.fromjs ([1,2,3,4]).findkey ((value,index,array)=>{return value%2 === 0; }) // 1 immutable.fromjs ([1,2,3,4]).findLastKey((value,index,array)=>{return value%2 === 0; }) / / 3Copy the code
FindEntry (), findLastEntry ()
Search for key:value pairs of elements that meet the criteria
Usage:
Immutable. FromJS ([1,2,3,4]). FindEntry ((value,index,array)=>{return value%2 === 0; }) // [1,2] Immutable.fromjs ([1,2,3,4]).findlastentry ((value,index,array)=>{return value%2 === 0; }) / / [3, 4]Copy the code
keyOf() lastKeyOf()
Function: Searches for the key corresponding to a value
Usage:
Immutable. FromJS ([1, 2, 3, 4]) keyOf (2) / / 1 Immutable. FromJS ([1, 2, 3, 4]). LastKeyOf (2) / / 1Copy the code
Max (), maxBy ()
Function: Find the maximum value
Usage:
Immutable.fromJS([1, 2, 3, 4]).max() //4
Immutable.fromJS([{a;1},{a:2},{a: 3},{a:4}]).maxBy((value,index,array)=>{
return value.get('a')
}) //{a:4}
Copy the code
The min (), minBy ()
Function: Find the minimum value
Usage:
Immutable.fromJS([1, 2, 3, 4]).min() //1
Immutable.fromJS([{a;1},{a:2},{a: 3},{a:4}]).minBy((value,index,array)=>{
return value.get('a')
}) //{a:1}
Copy the code
Create a subset
slice()
Just like the slice array in native JS, this array contains two arguments, start and end. Start represents the start position and end represents the end position, excluding the end element. If end is not included, the whole object is returned; if end is negative, the corresponding data (start, length-end) is returned. If start has only one and is negative, the last end element is returned.
Usage:
Immutable.fromJS([1, 2, 3, 4]).slice(0); / / [1, 2, 3, 4] Immutable. FromJS ([1, 2, 3, 4]). The slice (0, 2); / / [1, 2] Immutable. FromJS ([1, 2, 3, 4]). The slice (2); / / [3, 4] Immutable. FromJS ([1, 2, 3, 4]). The slice (0, 2); / / [1, 2]Copy the code
rest()
Function: Returns all elements except the first one
Usage:
Immutable. FromJS ([1, 2, 3, 4]). The rest () / / (2 and 4)Copy the code
butLast()
Function: Returns all elements except the last one
Usage:
Immutable. FromJS ([1, 2, 3, 4]). The rest () / / [1, 2, 3]Copy the code
skip()
Action: takes an argument n and returns all elements left after the first n elements are truncated
Usage:
Immutable. FromJS ([1, 2, 3, 4]). Skip (1) / / \ [2 4]Copy the code
skipLast()
Action: Takes an argument n and returns all elements left after the last n elements are truncated
Usage:
Immutable. FromJS ([1, 2, 3, 4]). Skip (1) / / [1, 2, 3]Copy the code
skipWhile()
Function: Returns all elements since the first return false
Immutable.fromJS([1, 2, 3, 4]).skipWhile(list.skipWhile((value,index,list)=>{ return value > 2; })) / / [1, 2, 3, 4] skipUntil ()Copy the code
Function: Returns all elements since the first return true
Immutable.fromJS([1, 2, 3, 4]).skipUntil(list.skipWhile((value,index,list)=>{ return value > 2; })) / / [3, 4]Copy the code
take()
Action: Returns the first n elements with an argument n
Usage:
Immutable. FromJS ([1, 2, 3, 4]), take (2) / / [1, 2]Copy the code
takeLast()
Action: Returns the last n elements with an argument n
Usage:
Immutable. FromJS ([1, 2, 3, 4]). TakeLast (2) / / [3, 4]Copy the code
takeWhile()
Function: Returns all elements from before the first return false
Immutable.fromJS([1, 2, 3, 4]).skipWhile(list.takeWhile((value,index,list)=>{ return value > 2; })) / / []Copy the code
takeUntil()
Function: Returns all elements before the first return true
Immutable.fromJS([1, 2, 3, 4]).skipUntil(list.takeUntil((value,index,list)=>{ return value > 2; })) / / [1, 2]Copy the code
Process the data
reduce()
Function: In the same way as reduce in js arrays, elements are processed in ascending order by index
Usage:
Immutable. FromJS ([1, 2, 3, 4]) reduce ((pre, next, index, arr) = > {the console. The log (pre + next) return the pre + next; }) // 3 6 10Copy the code
reduceRight()
Function: In the same way as reduce in js arrays, elements are processed in descending order by index
Usage:
Immutable. FromJS ([1, 2, 3, 4]) reduceRight ((pre, next, index, arr) = > {the console. The log (pre + next) return the pre + next; }) // 7 9 10Copy the code
every()
Check whether all elements in the whole object meet a certain condition, return true, otherwise return false.
Code:
Every ((value,index,arr)=>{return value > 2}) // falseCopy the code
some()
Function: Check whether all elements in the whole object meet a certain condition, if there is an element, return true, otherwise return false.
Code:
Immutable.fromjs ([1,2,3,4]).some((value,index,arr)=>{return value > 2}) // trueCopy the code
join()
Function: Joins an array in js. Change the quasi to a string
Usage:
Immutable. FromJS ([1, 2, 3, 4]). The join (', ') / / 1, 2, 3, 4Copy the code
isEmpty()
Function: Check whether it is empty
Usage:
Immutable.fromJS([]).isEmpty(); //true
Immutable.fromJS({}).isEmpty(); //true
Copy the code
count()
Function: Return the number of elements, can be customized conditions, return the number of conditions
Usage:
Constlist = Immutable. FromJS ([1, 2, 3, 4]); constmap = Immutable.fromJS({a:1,b:2,c:3,d:4}); list.count((value,index,list)=>{ return value > 2; }) //2map.count((value,index,list)=>{ return value > 2; / / 2})Copy the code
countBy()
What it does: Unlike count, countBy returns an object
Usage:
Constlist = Immutable. FromJS ([1, 2, 3, 4]); constmap = Immutable.fromJS({a:1,b:2,c:3,d:4}); list.countBy((value,index,list)=>{ return value > 2; } //{false: 2, true: 2}map.countBy((value,index,list)=>{ return value > 2; } //{false: 2, true: 2}Copy the code
reference
Immutable -js Official document