immutable学习
简介
js 中的对象时引用赋值,是可变的,新的对象简单的引用原始的对象,改变新的对象将影响到原始对象,这样虽然可以节约内存,但是当应用复杂后,会造成很大的隐患,一般的解决办法是进行浅拷贝和深拷贝来避免被修改,但是这样会造成内存的浪费,引用自Immutable 详解及 React 中实践
Immutable Data 就是一旦创建,就不能再被更改的数据。对其进行任何修改和删除操作都会返回一个新的对象,Immutable 使用了结构共享:如果对象树中的 一个节点发生变化,只修改这个节点和受它影响的父节点,其他节点则进行共享
Immutable API
is()
比较两个对象或数组的值是否相等,只要值相等就返回true,(只能比较 Map List类型的数据)
let arr = [1,2,3,4];
let $arr = List(arr);
let $arr2 = List(arr);
let arr3 = List(arr).toJS();
console.log($arr);
console.log($arr === $arr2); // false
console.log(Immutable.is($arr, $arr2)); // true
console.log(Immutable.is(arr3, $arr2)); // false 非 Map List类型比较返回false
类型转换
fromJS()
将普通的js Object 和 Array,深度的转换为不可变的 Map 和 List
toJS() toJSON()
深度转换成等值的js
let a = Immutable.fromJS([{a:111,b:222}, [3, 4, 5, 6]])
let b = a.toJS();
let c = a.toJSON();
console.log(b); // [{a:111,b:222}, [3, 4, 5, 6]]
console.log(c); // [{a:111,b:222}, [3, 4, 5, 6]]
toList() toMap()
浅度转换为 List Map
let a = Map({1:[1,[2,3,4],{a:11,b:22}],2:[222,333]});
let b = a.toList();
let c = b.toMap();
console.log(a.toJS()); // Object {1: Array[3], 2: Array[2]}
console.log(b.toJS()); // [Array[3], Array[2]]
console.log(c.toJS()); // Object {0: Array[3], 1: Array[2]}
toArray() toObject()
浅度转换成js数组或者对象,(不是给原生数组和对象使用的,原生js没有这些方法,会报错)
let a = Immutable.fromJS([{a:111,b:222}, [3, 4, 5, 6]])
let b = Immutable.fromJS({1 :{a:111,b:222},2: [3, 4, 5, 6]})
let c = a.toArray();
let d = b.toObject();
console.log(a); // List [Map, List]
console.log(b); // Map {1 : Map, 2 : List}
console.log(c); // [Map, List]
console.log(d); // {1 : Map, 2 : List}
List() Map()
列表,地图 ,不可变的
List.isList()
判断提供的值,是否是 List 类型数据
let arr = [1,2,3,4];
let $arr = List(arr);
console.log(List.isList(arr)); // false
console.log(List.isList($arr)); // true
List.of()
根据传入的值,创建一个列表
let $arr1 = List.of(1,2,3,6);
let $arr2 = List.of({a:999},8,[2,3,4]);
console.log($arr1.toJS()); // [1, 2, 3, 6]
console.log($arr2.toJS()); // [{a:999},8,[2,3,4]]
Map.isMap()
判断是否是 Map 类型
Map.of()
创建 Map
let $obj = Map.of('aa','bb','22','cc','33','11');
console.log('obj =' + $obj); // obj =Map { "aa": "bb", "22": "cc", "33": "11" }
.size
返回 对应类型数据的长度
let $arr1 = List.of(1,2,3,6);
let $arr2 = List.of({a:999},8,[2,3,4]);
console.log($arr1.size); // 4
console.log($arr2.size); // 3
.set(key, value)
根据传入的新的数据,返回一个新的 对应类型数据
- 如果key已经存在,旧的value会被替换
- List负数key 表示从 List 末尾开始计数
- index 大于 List 的 size 则 返回的 List 的 size 会包含 index
let $arr = List.of(1,2,3,6);
let $arr2 = $arr.set(9,222); // 表示第10(索引从0开始)位是222
let $arr3 = $arr.set(-1,999);
let $arr4 = $arr.set(-7,777);
console.log($arr.toJS()); // [1, 2, 3, 6] size : 4
console.log($arr2.toJS());
// [1, 2, 3, 6, undefined, undefined, undefined, undefined, undefined, 222] size : 10
console.log($arr3.toJS()); // [1, 2, 3, 999]
console.log($arr4.toJS()); // [777, undefined, undefined, 1, 2, 3, 6] size : 7
let a = Map({a:1, b:2, c:3});
let b = a.set('b',77);
let c = a.set('d',99);
console.log('b = ' + b); // b = Map { "a": 1, "b": 77, "c": 3 }
console.log('c = ' + c); // c = Map { "a": 1, "b": 2, "c": 3, "d": 99 }
.get(key)
返回根据key 对应的值
let $arr = List([1,2,3,List([11,22]),5]);
let str = $arr.get(2);
console.log($arr);
console.log(str); // 3
let map = Map({1:'one'});
console.log(map.get(1)); // undefined
console.log(map.get('1')); // one
.has(key)
判断是否存在 key 对应的 键(不是值),(只在第一层中查找)
let $arr = List([1,2,3,List([11,22]),5]);
let bl = $arr.has(3);
let bln = $arr.has(11);
console.log($arr);
console.log(bl); // true
console.log(bln); // false
.includes(value)
判断 是否存在 value 对应的值,(只在第一层中查找)
let $arr = List([1,[11,22,33,44],3]);
let bl = $arr.includes(3);
let bl2 = $arr.has(3);
let bln = $arr.includes(11);
console.log(bl); // true
console.log(bl2); // false
console.log(bln); // false
.first() .last()
返回第一个、最后一个值
let $arr = List([1,[11,22,33,44],3]);
let fir = $arr.first();
let las = $arr.last();
console.log(fir); // 1
console.log(las); // 3
.delete(key)
返回一个新的 List或者Map 不包括这个key 对应的值 ,(List 中 index 负数 ,表示从末尾开始查找)
let $arr = List.of(1,2,3,6);
let $arr2 = $arr.delete(2);
let $arr3 = $arr.remove(-3); // 使用remove(),功能一样
console.log($arr.toJS()); // [1, 2, 3, 6]
console.log($arr2.toJS()); // [1, 2, 6]
console.log($arr3.toJS()); // [1, 3, 6]
.insert(index,value) ,(no : Map)
返回一个新的 List ,在index 的位置 插入 新数据 value,原位置数据向后移一位,(index 为负数,表示从末尾索引)
let $arr = List.of(1,2,3,6);
let $arr2 = $arr.insert(2,99);
let $arr3 = $arr.insert(-3,88);
console.log($arr.toJS()); // [1, 2, 3, 6]
console.log($arr2.toJS()); // [1, 2, 99, 3, 6]
console.log($arr3.toJS()); // [1, 88, 2, 3, 6]
.clear()
返回一个空的List或者Map
let $arr = List.of(1,2,3,6);
let $arr2 = $arr.clear();
console.log($arr.toJS()); // [1, 2, 3, 6]
console.log($arr2.toJS()); // []
.push() .pop() .unshift() .shift() (no : Map)
类似js的数组方法 尾部添加、尾部删除、头部添加、头部删除,但是不同的是,返回的是新的List
let $arr = List.of(1,2,3,6);
let $arr2 = $arr.push(111);
let $arr3 = $arr.pop();
let $arr4 = $arr.unshift(1.01);
let $arr5 = $arr.shift();
console.log($arr.toJS()); // [1, 2, 3, 6]
console.log($arr2.toJS()); // [1, 2, 3, 6, 111]
console.log($arr3.toJS()); // [1, 2, 3]
console.log($arr4.toJS()); // [1.01, 1, 2, 3, 6]
console.log($arr5.toJS()); // [2, 3, 6]
.update()
返回更新的List或者Map
let a = Map({a:1, b:2, c:3});
let b = a.update('a',value => {
return value + 10;
});
let c = a.update('d','no',value => {
console.log(value); // no
return 20;
});
let d = a.update(map => {
console.log('map = ' + map); // map = Map { "a": 1, "b": 2, "c": 3 }
return map;
})
console.log('b = ' + b); // b = Map { "a": 11, "b": 2, "c": 3 }
console.log('c = ' + c); // c = Map { "a": 1, "b": 2, "c": 3, "d": 20 }
console.log(a === b); // false
console.log('d = ' + d); // d = Map { "a": 1, "b": 2, "c": 3 }
.merge()
用来合并,List 的合并会按照索引值替换,Map 按照 key值替换
let $arr = List([{a:110,b:220},22,33,44]);
let $arr2 = $arr.merge($arr, [99,{c:330, b:440}]);
console.log($arr.toJS()); // [{a:110,b:220},22,33,44]
console.log($arr2.toJS()); // [99,{c:330, b:440},33,44]
.mergeWith()
跟merge类似,但是可以处理逻辑,决定输出规则
let a = Map({a:1, b:2, c:3});
let b = Map({c:30, b:7, d:9});
let c = a.mergeWith((prev,next) => {
console.log(prev + '====' + next); // 3===30 2===7
return prev / next;
},b);
console.log('c = ' + c); // c = Map { "a": 1, "b": 0.2857142857142857, "c": 0.1, "d": 9 }
.mergeDeep() .mergeDeepWith()
跟 merge一样,但是会深度处理
let a = Immutable.fromJS({a:1, b:2, c:{d:33,e:44}});
let b = Immutable.fromJS({c:{d:333, f:555}, b:7, d:9});
let c = a.merge(b);
let d = a.mergeDeep(b);
let e = a.mergeDeepWith((prev, next) => {
console.log(prev + '====' + next); // 33====333 2====7
return prev / next;
}, b);
console.log('c = ' + c);
// c = Map { "a": 1, "b": 7, "c": Map { "d": 333, "f": 555 }, "d": 9 }
console.log('d = ' + d);
// d = Map { "a": 1, "b": 7, "c": Map { "d": 333, "e": 44, "f": 555 }, "d": 9 }
console.log('e = ' + e);
// e = Map { "a": 1, "b": 0.2857142857142857, "c": Map { "d": 0.0990990990990991, "e": 44, "f": 555 }, "d": 9 }
.setSize() (no : Map)
改变List 长度
- 新的size小于原size,则从后边剪切
- 新的size大于原size,则增加新的未定义的值
let $arr = List([{a:110,b:220},22,33,44]);
let $arr2 = $arr.setSize(7);
let $arr3 = $arr.setSize(2);
console.log($arr.toJS()); // [{a:110,b:220},22,33,44]
console.log($arr2.toJS()); // [{a:110,b:220},22, 33, 44, undefined, undefined, undefined]
console.log($arr3.toJS()); // [{a:110,b:220},22]
.setIn()
返回一个新的List或者Map 含有新设定的值
let a = Immutable.fromJS([{a:111,b:222}, 1, 2, [3, 4]])
let b = a.setIn([0, 'b'], -3);
let c = a.setIn([3, 0], 100);
console.log(b.toJS()); // [{a:111,b:-3}, 1, 2, [3, 4]]
console.log(c.toJS()); // [{a:111,b:222}, 1, 2, [100, 4]]
.getIn()
返回一个深层次的值
let a = Immutable.fromJS([{a:111,b:222}, 1, 2, [3, 4]])
let b = a.getIn([0, 'b']);
let c = a.getIn([3, 0]);
console.log(b); // 222
console.log(c); // 3
.hasIn()
深层次的查找,是否有相应的key
let a = Immutable.fromJS([{a:111,b:222}, [3, 4, 5, 6]])
let b = a.hasIn([0, 'b']);
let c = a.hasIn([1, 4]);
console.log(b); // true
console.log(c); // false
.deleteIn()
返回一个删除指定值的List或者Map
let a = Immutable.fromJS([{a:111,b:222}, 1, 2, [3, 4]])
let b = a.deleteIn([0, 'b']);
let c = a.deleteIn([3, 0]);
console.log(b.toJS()); // [{a:111}, 1, 2, [3, 4]]
console.log(c.toJS()); // [{a:111,b:222}, 1, 2, [4]]
.updateIn()
返回一个新的List或者Map
let a = Immutable.fromJS({a:1, b:2, c:{d:33,e:44}});
let b = a.updateIn(['c','d'],value => {
console.log(value); // 33
return 33333;
});
console.log('b = ' + b); // b = Map { "a": 1, "b": 2, "c": Map { "d": 33333, "e": 44 } }
.mergeIn() .mergeDeepIn()
查找里层,然后将里层跟新的合并
let a = Immutable.fromJS({a:1, b:2, c:{d:{g:33,h:66},e:44}});
let b = a.mergeIn(['c'],{d:{g:33333},f:88888});
let c = a.mergeDeepIn(['c'],{d:{g:33333},f:88888});
console.log('b = ' + b);
// b = Map { "a": 1, "b": 2, "c": Map { "d": Map { "g": 33333 }, "e": 44, "f": 88888 } }
console.log('c = ' + c);
// c = Map { "a": 1, "b": 2, "c": Map { "d": Map { "g": 33333, "h": 66 }, "e": 44, "f": 88888 } }
序列算法
.map()
遍历,也可以返回一个经过计算的与原类型相同的值,List Map 都可以
let a = Immutable.fromJS({a:[1,[2,3,4],{a:11,b:22}],b:[222,333]});
let b = a.map((x,y) => {
console.log(x); // List、List
console.log('---');
console.log(y); // a 、 b
return x.push('nn');
})
console.log(b.toJS()); // {a:Array[4],b:[222,333,"nn"]}
.filter() .filterNot()
过滤(过滤得到满足条件的、过滤得到不满足条件的)
let a = Immutable.fromJS({a:[1,[2,3,4],{a:11,b:22}],b:[222,333]});
let b = a.filter((x,y) => {
return x.size >= 3;
})
console.log(b.toJS()); // {a:Array[3]}
.reverse() .sort()
类似js原生的数组方法 反向重组、排序
.slice()
类似原生js数组的方法 抽取
let a = Immutable.fromJS([1,[2,3,4],'nn',{a:11,b:22}]);
let b = a.slice(1);
let c = a.slice(1,3);
console.log('b ' + b); // b List [ List [ 2, 3, 4 ], "nn", Map { "a": 11, "b": 22 } ]
console.log('c ' + c); // c List [ List [ 2, 3, 4 ], "nn" ]
.concat()
类似原生js数组的方法 拼接
let a = Immutable.fromJS([1,[2,3,4],'nn',{a:11,b:22}]);
let b = a.concat(['ddd']);
console.log('b ' + b); // b List [ 1, List [ 2, 3, 4 ], "nn", Map { "a": 11, "b": 22 }, "ddd" ]
.splice()
类似原生js数组的方法 替换
let a = Immutable.fromJS([1,[2,3,4],'nn',{a:11,b:22}]);
let b = a.splice(0,2,['pp']);
console.log('b ' + b); // b List [ pp, "nn", Map { "a": 11, "b": 22 } ]
.join()
类似原生js数组的方法 链接成字符串
其他方法
.forEach()
遍历
let a = Immutable.fromJS({a:[1,[2,3,4],{a:11,b:22}],b:[222,333]});
a.forEach((value,key,some) => {
console.log('value ' + value);
// value List [ 1, List [ 2, 3, 4 ], Map { "a": 11, "b": 22 } ]
console.log('key ' + key);
// key a
console.log('some ' + some);
// some Map { "a": List [ 1, List [ 2, 3, 4 ], Map { "a": 11, "b": 22 } ], "b": List [ 222, 333 ] }
});
.rest() .butLast()
抽取 部分除了 第一个或者最后一个
let a = Immutable.fromJS([1,[2,3,4],'nn',{a:11,b:22}]);
let b = a.rest();
let c = a.butLast();
console.log('a ' + a); // a List [ 1, List [ 2, 3, 4 ], "nn", Map { "a": 11, "b": 22 } ]
console.log('b ' + b); // b List [ List [ 2, 3, 4 ], "nn", Map { "a": 11, "b": 22 } ]
console.log('c ' + c); // c List [ 1, List [ 2, 3, 4 ], "nn" ]
isEmpty()
判断是否为空
let a = Immutable.fromJS([1,[2,3,4],'nn',{a:11,b:22}]);
let b = Immutable.fromJS([]);
console.log(a.isEmpty()); // false
console.log(b.isEmpty()); // true