前言
今天在用 immutable 改写以前的旧代码. 数据的嵌套结构有可能很深的情况, 内部对于数据的增删改查和各种循环递归操作有很多. 用了 immutable.JS (其实也配合使用了 TypeScript, 效果更佳) 来改造了下. 一个总结体验那就是爽~
immutable 初相识
immutable 的英文意思是 "不可变的". 从名字就已经体现出 immutable.JS 的精髓了. 在 immutable 的世界观里, 一切都是不可变的数据. 对 Immutable 数据的修改会返回一个新的 Immutable 对象.
而传统的 JS 里十分让人头疼的一点就是对象的数据传递是引用传递, 更新了新的对象也会影响原有的对象. 从而使用各种 deepExtend, deepCopy 方法来解决这个问题. 而使用 immutable.JS 就没有这个烦恼.
举个栗子:
- let obj1 = Immutable.Map({
- a: 1, b: 2, c: 3
- })
- let obj2 = obj1
- obj2 === obj1
- // return true(此时 obj2 实例和 obj1 实例指向了同一个地址)
- obj2 = obj2.set("b",4)
- // 此时 obj2 已经被更新, 指向了另一个地址
- obj2 === obj1
- // return false
- // 改变 obj2 并不影响 obj1
常用的概念和操作
常用的对象
Map: 键值对结构, 通常对应 JS 中的 object 结构转换过来的类型. 但是和 JS 的 object 的很多特性有明显的区分.
Object 只接受字符串作为键名, 然而 Map 接受任何类型的数据作为键名.
- let obj = {
- 1: "one"
- }
- Object.keys(obj) // [ "1" ]
- console.log(obj["1"], obj[1]) // "one","one"
- let map = Map(obj)
- console.log(map.get("1"), map.get(1)) // "one", undefined
Map 支持键值对的遍历 (map,forEach,filter) 等操作. 大大方便了 JS 中 Object.keys()来遍历对象的写法
2. OrderedMap: 一种有序的 Map 类型. 弥补了 Object 对象无序的缺憾.
3. List: 有序列表, 对应 JS 中的 Array
4. Set: 不可重复的列表
常用的操作
1. 和 JS 数据类型相互转化
Immutable.Map({}) 对象换成 Map
Immutable.List([]) 数组换成 List
Immutable.formJS()
识别传入的数据并自动转换成相应 Map | List 类型
对于 Immutable 对象, 有 toJS(), toJSON(), toArray(), toObject()方法转换成相应的原生 JS 结构.
2. 判断两个对象的值是否相等
- let obj1 = Immutable.Map({
- a: 1, b: 2, c: 3
- })
- let obj2 = Immutable.Map({
- a: 1, b: 2, c: 3
- })
- Immutable.is(obj1, obj2); // or obj1.equals(obj2)
- // return ture
3. 深度取值
- let map1 = Immutable.Map({
- a: {
- d: {
- target : 1
- }
- }, b: 2, c: 3
- })
- const target = Immutable.getIn(map1, ["a","d","target"])
- // target: 1
4. 深度赋值
有一个 cursor(游标)的概念, 可以进行深度赋值的操作. 但会在下一个版本即将被废弃. 建议使用 setIn 来代替.
- let map1 = Immutable.Map({
- a: {
- d: {
- target : 1
- }
- }, b: 2, c: 3
- })
- map1 = Immutable.setIn(map1, ["a","d","target"], 4)
- // map1: {
- a: {
- d: {
- target : 4
- }
- }, b: 2, c: 3
- }
5. 浅合并(类似于 Object.assign, 只合并了第一层)
- const map1 = Immutable.Map({
- a: {
- d: {
- target : 1
- }
- }
- });
- const map2 = Immutable.Map({
- a: {
- c: 1
- }
- });
- const map3 = Immutable.merge(map1,map2)
- console.log(map3.toJS())
- // {
- a: {
- c: 1
- }
- }
6. 深度合并
- const map1 = Immutable.Map({
- a: {
- d: {
- target : 1
- }
- }
- });
- const map2 = Immutable.Map({
- a: {
- c: 1
- }
- });
- const map3 = Immutable.mergeDeep(map1,map2)
- console.log(map3.toJS())
- // {
- a: {
- c: 1, d: {
- target : 1
- }
- }
- }}
优势
1. 节省内存
使用了 Trie 数据结构来进行储存. 使用了结构共享, 即如果对象树中一个节点发生变化, 只修改这个节点和受它影响的父节点, 其它节点则进行共享.
比如对象
- const data = {
- to: 7,
- tea: 3,
- ted: 4,
- ten: 12,
- A: 15,
- i: 11,
- in: 5,
- inn: 9
- }
根据 trie 结构, 存储的结构类似于
如果更改了了 tea 字段 3 -\> 14, 那么只需改变四个节点, 来更新形成新的树, 这就是结构共享.
2. 提升计算性能
使用了 Trie 数据结构. 避免深度比较. 如果两个对象的值相等. 那么他们的 hashCode 也相等. 从而比较 hashCode 即可比较两个对象的值是否相等, 避免了深度比较.
3. 拥抱函数式编程
4. 使用便利
因为数据是不可变的. 同时提供的 API 面向开发者也十分友好.
使用 immutable 的注意事项
1. 变量命名
非常值得注意的一个点. 因为可能引用了其他的库或者文件, 使得代码里存在 immutable 数据和非 immutable 数据. 所以 immutable 变量需要加上 $$ 前缀来区分
2.API 上的习惯
赋值操作之后要修改原数据记得要赋值. 不然无法更新数据.
$$data = $$data.set("hello","immutable")
3. 无法使用 function 传值来修改数据
- let $$data = Map({
- hello: "immutable"
- });
- function changeData($$data){
- $$data = $$data.set("hello","world")
- }
- changeData($$data)
- console.log($$data.toJS())
- // {
- hello: "immutable"
- }
如上, $$data 并不会改变. 所以在写改变数据的方法的时候需要返回新值. 然后覆盖旧值.
- let $$data = Map({
- hello: "immutable"
- });
- function changeData($$data){
- return $$data.set("hello","world")
- }
- $$data = changeData($$data)
- console.log($$data.toJS())
- // {
- hello: "world"
- }
4. 为了性能和节省内存, Immutable.JS 会努力避免创建新的对象. 如果没有数据变化发生的话.
- const {
- Map
- } = require('immutable')
- const originalMap = Map({
- a: 1, b: 2, c: 3
- })
- const updatedMap = originalMap.set('b', 2)
- updatedMap === originalMap // return ture
如上代码虽然进行了一顿操作. 然而数据并没有改变. 所以 updatedMap 和 originalMap 还是指向了同一个对象.
- const updatedMap = originalMap.set('b', 4)
- updatedMap === originalMap
- // return false
此时返回 false
5.Immutable 的使用场景
虽然 immutable 有种种好处, 但并不是在所有场景都建议使用 Immutable, 对于数据结构复杂, 操作很多的使用 immutable 比较合适. 但对于简单的应用场景, 还是使用原生的 JS 吧.
来源: https://juejin.im/entry/5bce9620518825777f09390d