FROM URL:https://juejin.im/post/59df1a69f265da43346ee96a

将数据视为不可变,将给你带来很多好处。事实上,这是也React背后的原理:React的元素是不可变的。
但是用Immutable.js有什么好处呢?

假定有一个非常巨大的对象…

这里有100,000条待办事项:
var todos = {

t79444dae: { title: 'Task 50001', completed: false },
t7eaf70c3: { title: 'Task 50002', completed: false },
t2fd2ffa0: { title: 'Task 50003', completed: false },
t6321775c: { title: 'Task 50004', completed: false },
t2148bf88: { title: 'Task 50005', completed: false },
t9e37b9b6: { title: 'Task 50006', completed: false },
tb5b1b6ae: { title: 'Task 50007', completed: false },
tfe88b26d: { title: 'Task 50008', completed: false },

(100,000 items)
}我要把第50,005条任务的completed改为ture。

用普通的JavaScript对象

function toggleTodo (todos, id) {
return Object.assign({ }, todos, {
id: Object.assign({ }, todosid, {
completed: !todosid.completed
})
})
}

var nextState = toggleTodo(todos, 't2148bf88')这项操作运行了134ms。
为什么用了这么长时间呢?因为当使用Object.assign,JavaScript会从旧对象(浅)复制每个属性到新的对象。
我们有100,000条待办事项,所以意味着有100,000个属性需要被(浅)复制。
这就是为什么花了这么长时间的原因。
在JavaScript中,对象默认是可变的。
当你复制一个对象时,JavaScript不得不复制每一个属性来保证这两个对象相互独立。
为什么用Immutable.js代替普通js对象?_第1张图片
100,000个属性被(浅)复制到新的对象。

使用Immutable.js

var todos = Immutable.fromJS({

t79444dae: { title: 'Task 50001', completed: false },
t7eaf70c3: { title: 'Task 50002', completed: false },
t2fd2ffa0: { title: 'Task 50003', completed: false },
t6321775c: { title: 'Task 50004', completed: false },
t2148bf88: { title: 'Task 50005', completed: false },
t9e37b9b6: { title: 'Task 50006', completed: false },
tb5b1b6ae: { title: 'Task 50007', completed: false },
tfe88b26d: { title: 'Task 50008', completed: false },

(100,000 items)
})

// 使用updeep
function toggleTodo (todos, id) {
return u({

  completed: (completed) => !completed
}

}, todos)
}

var nextState = toggleTodo(todos, 't2148bf88')这项操作运行了1.2ms。速度提升了100倍。
为什么会这么快呢?

可持久化的数据结构

可持久化的数据结构强制约束所有的操作将返回新版本数据结构并且保持原有的数据结构不变,而不是直接修改原来的数据结构。
这意味着:所有的可持久化数据结构是不可变的。
鉴于这个约束,第三方库在应用可持久化数据结构后可以更好的优化性能。

性能提升

为了直观的观察,让我们尝试一个小小例子。
键值对映射数据:
为什么用Immutable.js代替普通js对象?_第2张图片
我们可以用一个普通的JavaScript对象来保存:
const data = {
to: 7,
tea: 3,
ted: 4,
ten: 12,
A: 15,
i: 11,
in: 5,
inn: 9
}
转换成一棵数据树,像这样:

为什么用Immutable.js代替普通js对象?_第3张图片
图片来源: 维基百科
通常来讲,你可以从根节点沿着上图的路径来获取你想要的值。
如果你想获取data.in,从根节点开始,沿着i,n,就可以到达值为5的节点。
如何去修改呢?
比如我们想把键为tea的值3改成14。
我要建造一个新的树,并且尽可能重用已经存在的节点
为什么用Immutable.js代替普通js对象?_第4张图片
绿色表示新建的节点。
为什么用Immutable.js代替普通js对象?_第5张图片
灰色的节点失去的索引,将会被回收
正如你所看到的,我们只是重新创建了4个新的节点来更新这个树。其他节点都被重用了。
这叫 结构共享
Immutable.js就是通过这种方式实现Immutable.Map。创建一个树,每个节点最多有32个分支。
为什么用Immutable.js代替普通js对象?_第6张图片
这张图展示了一个真实的Immutable.Map
当我们更新一个节点,只有几个节点需要被重新创建。
Immutable.js通过创建多种类型的节点来保持树结构的紧凑和性能:

为什么用Immutable.js代替普通js对象?_第7张图片

万物皆有两面性

请不要认为这篇文章的意思是“你应该经常使用Immutable.js。”,准确的讲,我只是告诉你用它的所有好处,以及为什么要使用它。
当我在写代码的时候,我首先会用普通的JavaScript对象和数组,当我使用Immutable.js时,我需要非常确定,比如一个对象包含10,000个属性。我几乎从不使用Immutable.js,因为大多数时候的对象都很小。

作者:缪宇
链接:https://juejin.im/post/59df1a69f265da43346ee96a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。