参考链接:
https://segmentfault.com/a/1190000017294051
https://zhuanlan.zhihu.com/p/101534155
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。
Immutable好在哪?
空间上
直观上看,改善最大的是内存/空间复杂度,从上图中就能看出,当我想拷贝一份新对象出来时,Immutable可以做到尽可能的内存共享,同时保证返回新对象。
时间上
结合实际应用,会发现immuable在时间复杂度上的优化也有大作为。
回想一下redux的使用,当我们想修改一个state并更新视图,在reducer中是不允许直接修改当前的state的,我们需要
- 拷贝一份copyData出来
- 修改copyData
- 返回copyData,更新视图
问题就出在这个拷贝操作上,想象一下我们有一个Array(10000),且每一项都是一个多层对象,当我们仅需要修改其中一项属性时,却需要深拷贝整个数组,这会带来巨大的耗时。
模拟一下
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js" integrity="sha512-myCdDiGJRYrvRb/VuJ67ljifYTJdc1jdEvL4c4ftX9o3N6EAnmD83c/7l2/91RCINZ7c8w21tiXDT7RDFjdc3g==" crossorigin="anonymous"></script>
function DeepClone (obj) {
if (obj === null || typeof obj !== 'object') return obj;
var cpObj = obj instanceof Array ? [] : {};
for (var key in obj) cpObj[key] = DeepClone(obj[key]);
return cpObj;
}
// 用于统计时长 iterations - fn迭代次数
function benchmark(iterations, f) {
var start = new Date();
for (var i = 0; i < iterations; i++) {
f();
}
var end = new Date();
console.log("Elapsed time: " + (end - start) + " msec");
}
let jsArr = (new Array(50000)).fill({name:'haha',age:20})
let immuArr = Immutable.List(jsArr)
benchmark(1,()=>{
let immu = immuArr.set(200,'change')
// 0ms
let newJsArr = immu.toJS(immu)
// 10ms
})
benchmark(1,()=>{
let newJsArr = DeepClone(jsArr)
newJsArr[200] = 'change'
// 20ms
})
结果表明,当我在一个50000长的对象数组中修改某一属性,用普通Js实现深拷贝+修改,耗时20ms,而使用immutable类型的数据实现不到1ms。
即使在完成后把immutable类型转回Js类型,时间也更短些(一般不会这么做)