immutable的应用

既然说到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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章