既然说到immutable,那什么是immutable呢?
immutable Data就是一旦被创建,就不能再被更改的数据,对immutable对象的任何修改,包括增删改查都会返回一个immutable对象,他实现的原理是Persistent Data Structure持久化数据结构,也就是使用旧数据创建新数据的时候,要保证旧数据可用且不变,同时为了避免deepCopy把所有节点都复制一遍带来的性能损耗,immutable使用了Structure Sharing(结构共享),即:如果对象数中一个节点发生变化,只修改这一个节点,和受它影响的父节点,其他节点进行共享;
为什么使用immutable呢?
使用他的具体原因:
它是一个完全独立的库,无论基于什么框架都可以用它。
意义在于它弥补了 Javascript 没有不可变数据结构的问题.
由于是不可变的,可以放心的对对象进行任意操作。
在 React 开发中,频繁操作state对象或是 store ,配合 immutableJS 快、安全、方便
熟悉 React.js 的都应该知道, React.js 是一个 UI = f(states) 的框架,为了解决更新的问题, React.js 使用了 virtual dom , virtual dom 通过 diff 修改 dom ,来实现高效的 dom 更新。
但是有一个问题。当 state 更新时,如果数据没变,你也会去做 virtual dom 的 diff ,这就产生了浪费。这种情况其实很常见
this.state = {count: 0}
this.setState({count: 0});// 组件 state 并未被改变,但仍会触发 render 方法
当然你可能会说,你可以使用 PureRenderMixin 来解决呀, PureRenderMixin 是个好东西,我们可以用它来解决一部分的上述问题
但 PureRenderMixin 只是简单的浅比较,不使用于多层比较。那怎么办?自己去做复杂比较的话,性能又会非常差
方案就是使用 immutable.js 可以解决这个问题。因为每一次 state 更新只要有数据改变,那么 PureRenderMixin 可以立刻判断出数据改变,可以大大提升性能
对比Object.assign
在JavaScript中,对象默认是可变的。当你复制一个对象时,JavaScript不得不复制每一个属性来保证这两个对象相互独立。100,000个属性被(浅)复制到新的对象。浅拷贝是需要时间的;
因为当使用Object.assign,JavaScript会从旧对象(浅)复制每个属性到新的对象。如果简单数据的话,使用Object.assign还是没有多大影响的,但是数据量大的时候会增加,浅拷贝的时间会增加,这样性能上有一定的影响,这就体现出immutable的优势。
Immutable 的几种数据类型
List : 有序索引集,类似 JavaScript 中的 Array 。
Map : 无序索引集,类似 JavaScript 中的 Object 。
OrderedMap : 有序的 Map ,根据数据的 set() 进行排序。
Set : 没有重复值的集合。
OrderedSet : 有序的 Set ,根据数据的 add 进行排序。
Stack : 有序集合,支持使用 unshift() 和 shift() 添加和删除。
Range() : 返回一个 Seq.Indexed 类型的集合,这个方法有三个参数, start 表示开始值,默认值为 0 , end 表示结束值,默认为无穷大, step 代表每次增大的数值,默认为 1 .如果 start = end ,则返回空集合。
Repeat() : 返回一个 vSeq.Indexe 类型的集合,这个方法有两个参数, value 代表需要重复的值, times 代表要重复的次数,默认为无穷大。
Record : 一个用于生成 Record 实例的类。类似于 JavaScript 的 Object ,但是只接收特定字符串为 key ,具有默认值。
Seq : 序列,但是可能不能由具体的数据结构支持。
Collection : 是构建所有数据结构的基类,不可以直接构建
上面那么多常用的也就是 List 和 Map
immutable使用 :
安装
npm i immutable --save
方法汇总:
fromJS,set,get,setIn,getIn,without,update,updateIn,merge,mergeDeep, delete,has,hasIn…
import { fromJS,Map, List } from 'immutable';
const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } },g:9 });
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } },g:9 }
console.log(nested2.getIn([ 'a', 'b', 'd' ]),nested2.get('a')); // 6
const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
const nested5 = nested4.update('g', 10)
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } },g:10 }
const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
const map2 = Map({ c: 10, a: 20, t: 30 });
const obj = { d: 100, o: 200, g: 300 };
const map3 = map1.merge(map2, obj);
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const array = [ 7, 8, 9 ];
const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
将js对象或者数组转变成immutable对象
import { fromJS } from 'immutable';
const initialState = fromJS({
homeList: [],
obj:{name: 'xixi',age:20},
inputValue: ''
});
获取属性
state.get('homeList'); // 获取store中的homeList
statae.get(['obj', 'name']); // 获取obj组件中name
改变属性
state.set('inputValue', action.value); // 设置单个属性值
// 设置多个属性
state.merge({
homeList: fromJS(action.value), // 由于action.value是js对象所以要转成immutable对象
});
将immutable对象转成js对象
state.get('homeList').toJS(); // 把todoList转成js数组
删除对象中的某一项,参数是对象中的key
state.delete('inputvalue')
删除对象中的某一项
state.deleteIn("obj","name")
has() hasIn() 检查是否有某个key
// List
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).has('0')); // true
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).hasIn([3, 'b'])); // true
// Map
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).has('a')); // true
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).hasIn(['a', 'a3'])); // true
更新对象,以及更新对象中的某一项
const nested5 = state.update('inputValue', 10)
const nested3 = state.updateIn(['obj','age'], value => value + 1);
Map.of()
console.log(Map.of('key1','value1','key2','value2','key3','value3').toJS()); // {key1: "value1", key2: "value2", key3: "value3"}
List.of()
console.log(List.of({x:1}, 2, [3], 4).toJS()); // [{x:1}, 2, [3], 4]
判断是否是一个Map或者List
1、Map判断
判断是否是一个 Map , 对原生 Object 不生效
console.log(Map.isMap({})); // false
console.log(Map.isMap(Map({}))); // true
2、List判断
判断是否是一个 List , 对原生 Array 不生效
console.log(List.isList([])); // false
console.log(List.isList(List([]))); // true
获取大小
1、size
// list
console.log(List([1,2,3,4]).size);// 4
console.log(List.of(1, 2, 3, 4).size);// 4
// map
console.log(Map({key: "value2", key1: "value1"}).size);// 2
console.log(Map.of({x:1}, 2, [3], 4).size);// 2
count()
// map
console.log(Immutable.fromJS({key: "value2", key1: "value1"}).count());// 4
// 可以定制条件,来确定大小
console.log(Immutable.fromJS({key: 1, key1: 34}).count((value, key, obj) => {
return value > 3;
}));// 1 value大于3的有两个
如有错误请指出,谢谢。
参考:
https://blog.csdn.net/m0_37527015/article/details/84338831
https://www.cnblogs.com/chris-oil/p/8494337.html