[js] Immutable
Map:键值对集合,对应于 Object,ES6 也有专门的 Map 对象
List:有序可重复的列表,对应于 Array
Set:无序且不可重复的列表
List可以使用部分与原本Array同名的方法
map
var map1 = Immutable.Map({a: 1, b: 3});
var map2 = map1.set('a', 2);
console.log(map1.get('a')); // 1
console.log(map2.get('a')); // 2
// 1. Map 大小
const map1 = Immutable.Map({ a: 1 });
console.log(map1.size)
// => 1
// 2. 新增或取代 Map 元素
// set(key: K, value: V)
const map2 = map1.set('a', 5);
console.log(map2.get('a'))//5
console.log(map2.toJS())
// => Map { "a": 5 }
// 3. 删除元素
// delete(key: K)
const map3 = map1.delete('a');
console.log(map3.size)//0
console.log(map3.toJS())
// => Map {}
// 4. 清除 Map 內容
const map4 = map1.clear();
console.log(map4.size)//0
console.log(map4.toJS())
// => Map {}
// 5. 更新 Map 元素
// update(updater: (value: Map<K, V>) => Map<K, V>)
// update(key: K, updater: (value: V) => V)
// update(key: K, notSetValue: V, updater: (value: V) => V)
const map5 = map1.update('a', () => (7))
console.log(map5.get('a'))//7
console.log(map5.toJS())
// => Map { "a": 7 }
// 6. 合并 Map
const map6 = Immutable.Map({ b: 3 });
map1.merge(map6);
console.log(map1.toJS())
console.log(map6.toJS())
// => Map { "a": 1, "b": 3 }
List
const List= Immutable.List;
// 1. 取得 List 长度
const arr1 = List([1, 2, 3]);
console.log(arr1.size)
// => 3
// 2. 新增或取代 List 元素內容
// set(index: number, value: T)
// 将index 位置的元素替换
const arr2 = arr1.set(-1, 7);
console.log(arr2.toJS())
// => [1, 2, 7]
const arr3 = arr1.set(4, 0);
console.log(arr3.toJS())
// => [1, 2, 3, undefined, 0]
// 3. 删除 List 元素
// delete(index: number)
// 删除 index 位置的元素
const arr4 = arr1.delete(1);
console.log(arr4.toJS())
// => [1, 3]
// 4. 插入元素到 List
// insert(index: number, value: T)
// 在 index 位置插入 value
const arr5 = arr1.insert(1, 8);
console.log(arr5.toJS())
// => [1, 8, 2, 3]
// 5. 清空 List
// clear()
const arr6 = arr1.clear();
console.log(arr6.toJS())
// => []
Set
const Set = Immutable.Set;
// 1. 建立 Set
const set1 = Set([1, 2, 3]);
console.log(set1.toJS());
// => Set { 1, 2, 3 }
// 2. 新增元素
const set2 = set1.add(1).add(5);
console.log(set2.toJS());
// => Set { 1, 2, 3, 5 }
// 由于 Set 为不能重复集合,故 1 只能出现一次
// 3. 刪除元素
const set3 = set1.delete(3);
console.log(set3.toJS());
// => Set { 1, 2 }
// 4. 取合集
const set4 = Set([2, 3, 4, 5, 6]);
console.log(set1.union(set4).toJS());
// => Set { 1, 2, 3, 4, 5, 6 }
// 5. 取交集
console.log(set1.intersect(set4).toJS());
// => Set { 2, 3 }
// 6. 取差集
console.log(set1.subtract(set4).toJS());
// => Set { 1 }
console.log(set4.subtract(set1).toJS());
// => Set { 6, 5, 4}
Structural Sharing
const obj = {
count: 1,
list: [1, 2, 3, 4, 5]
}
var map1 = Immutable.fromJS(obj);
var map2 = map1.set('count', 4);
console.log(map1.list === map2.list); // true
Support Lazy Operation
let l = Immutable.Range(1, Infinity)
.map(n => -n)
//? Error: Cannot perform this action with an infinite size.
console.log(l)//n {size: Infinity}
let z = Immutable
.Range(1, Infinity)
.map(n => -n)
.take(2)
.reduce((r, n) => r + n, 0);
// -3
console.log(z)
react 性能优化
console.log({ foo: 'app' }==={ foo: 'app' })//false
var SomeRecord = Immutable.Record({ foo: null });
var x = new SomeRecord({ foo: 'app' });
var y = x.set('foo', 'app');
console.log(x === y); // true
// 原来的写法
let foo = {a: {b: 1}};
let bar = foo;
bar.a.b = 2;
console.log(foo.a.b); // 打印 2
console.log(foo === bar); // 打印 true
// 使用 immutable.js 后
import Immutable from 'immutable';
foo = Immutable.fromJS({a: {b: 1}});
bar = foo.setIn(['a', 'b'], 2); // 使用 setIn 赋值
console.log(foo.getIn(['a', 'b'])); // 使用 getIn 取值,打印 1
console.log(bar.getIn(['a', 'b'])); //2
console.log(foo === bar); // 打印 false
Iterable
The Iterable is a set of (key, value) entries which can be iterated, and is the base class for all collections in immutable, allowing them to make use of all the Iterable methods (such as map and filter).
class Iterable<K, V>
Discussion
Note: An iterable is always iterated in the same order, however that order may not always be well defined, as is the case for the Map and Set.
Conversion to JavaScript types
toJS()
Deeply converts this Iterable to equivalent JS.
toJS(): any
alias
toJSON()
Discussion
Iterable.Indexeds, and Iterable.Sets become Arrays, while Iterable.Keyeds become Objects.
Reading values
get()
Returns the value associated with the provided key, or notSetValue if the Iterable does not contain this key.
get(key: K, notSetValue?: V): V
Discussion
Note: it is possible a key may be associated with an undefined value, so if notSetValue is not provided and this method returns undefined, that does not guarantee the key was not found.
getIn()
Returns the value found by following a path of keys or indices through nested Iterables.
getIn(searchKeyPath: Array<any>, notSetValue?: any): any
getIn(searchKeyPath: Iterable<any, any>, notSetValue?: any): any
Map
Immutable Map is an unordered Iterable.Keyed of (key, value) pairs with O(log32 N) gets and O(log32 N) persistent sets.
class Map<K, V> extends Collection.Keyed<K, V>
Discussion
Iteration order of a Map is undefined, however is stable. Multiple iterations of the same Map will iterate in the same order.
Map's keys can be of any type, and use Immutable.is to determine key equality. This allows the use of any value (including NaN) as a key.
Because Immutable.is returns equality based on value semantics, and Immutable collections are treated as values, any Immutable collection may be used as a key.
Map().set(List.of(1), 'listofone').get(List.of(1));
// 'listofone'
Any JavaScript object may be used as a key, however strict identity is used to evaluate key equality. Two similar looking objects will represent two different keys.
Implemented by a hash-array mapped trie.
Construction
Map()
Creates a new Immutable Map.
Map<K, V>(): Map<K, V>
Map<K, V>(iter: Iterable.Keyed<K, V>): Map<K, V>
Map<K, V>(iter: Iterable<any, Array<any>>): Map<K, V>
Map<K, V>(array: Array<Array<any>>): Map<K, V>
Map<V>(obj: {[key: string]: V}): Map<string, V>
Map<K, V>(iterator: Iterator<Array<any>>): Map<K, V>
Map<K, V>(iterable: Object): Map<K, V>
Discussion
Created with the same key value pairs as the provided Iterable.Keyed or JavaScript Object or expects an Iterable of [K, V] tuple entries.
var newMap = Map({key: "value"});
var newMap = Map([["key", "value"]]);
Keep in mind, when using JS objects to construct Immutable Maps, that JavaScript Object properties are always strings, even if written in a quote-less shorthand, while Immutable Maps accept keys of any type.
var obj = { 1: "one" };
Object.keys(obj); // [ "1" ]
obj["1"]; // "one"
obj[1]; // "one"
var map = Map(obj);
map.get("1"); // "one"
map.get(1); // undefined
Property access for JavaScript Objects first converts the key to a string, but since Immutable Map keys can be of any type the argument to get() is not altered.
fromJS()
Deeply converts plain JS objects and arrays to Immutable Maps and Lists.
fromJS(json: any, reviver?: (k: any, v: Iterable<any, any>) => any): any
Discussion
If a reviver is optionally provided, it will be called with every collection as a Seq (beginning with the most nested collections and proceeding to the top-level collection itself), along with the key refering to each collection and the parent JS object provided as this. For the top level, object, the key will be "". This reviver is expected to return a new Immutable Iterable, allowing for custom conversions from deep JS objects.
This example converts JSON to List and OrderedMap:
Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40}, function (key, value) {
var isIndexed = Immutable.Iterable.isIndexed(value);
return isIndexed ? value.toList() : value.toOrderedMap();
});
// true, "b", {b: [10, 20, 30]}
// false, "a", {a: {b: [10, 20, 30]}, c: 40}
// false, "", {"": {a: {b: [10, 20, 30]}, c: 40}}
If reviver is not provided, the default behavior will convert Arrays into Lists and Objects into Maps.
reviver acts similarly to the same parameter in JSON.parse.
Immutable.fromJS is conservative in its conversion. It will only convert arrays which pass Array.isArray to Lists, and only raw objects (no custom prototype) to Map.
Keep in mind, when using JS objects to construct Immutable Maps, that JavaScript Object properties are always strings, even if written in a quote-less shorthand, while Immutable Maps accept keys of any type.
var obj = { 1: "one" };
Object.keys(obj); // [ "1" ]
obj["1"]; // "one"
obj[1]; // "one"
var map = Map(obj);
map.get("1"); // "one"
map.get(1); // undefined
Property access for JavaScript Objects first converts the key to a string, but since Immutable Map keys can be of any type the argument to get() is not altered.
"Using the reviver parameter"