什么是immutable
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
其中有 3 种最重要的数据结构:
Map:键值对集合,对应于 Object,ES6 也有专门的 Map 对象
List:有序可重复的列表,对应于 Array
Set:无序且不可重复的列表
Map 的介绍及 API
// --------- Map 的介绍及 API ------------
// Map 对应原生 js 的 Object 结构, 是无序的键值对集合
// 创建Map,注意:Map是工厂方法,不能使用new初始化
const {Map, List, OrderedMap} = require('immutable')
const m1 = Map({
x: 1,
y:2
})
console.log('m1:', m1)
// set 设定值 set(key, value)
const m2 = m1.set('z', 666)
console.log('m2:', m2)
// 原生js中的键 key 要求是一个字符串,在immutable中并没有这个要求
const m3 = m1.set(List([1]), {username:'张三'})
console.log('m3:', m3)
// get 取值
console.log('m2:', m2.get('z'))
// delete 删除值 delete(key)
const d1 = Map({
username:'zhangsan',
age: 18
})
const d2 = d1.delete('age')
console.log('d2:', d2)
// deleteAll 批量删除 deleteAll([key1, key2, ...keyN]) 删除 N 个key值,只返回一次新的对象
const dal = Map({
x:1,
y:2,
z:3,
username: 'zhangsan',
age:18
})
const dal2 = dal.deleteAll(['x','z']) // 删除 x 和 z
console.log('dal2:', dal2)
// clear 清除并返回新的 Map
const cls = dal.clear();
console.log('cls:', cls)
// update 更新, update(key, callback) callback 可按照某种逻辑把value再加工一次
const sal = Map({
name:'zhangsan',
salary: 1000
})
const sal2 = sal.update('salary:', x => x*2)
console.log('sal2:', sal2)
// merge 把 N 个 Map 合并成一个 Map
const mer1 = Map({
x:1,
y:2
})
const mer2 = Map({
y:666,
z:3
})
const mer3 = mer1.merge(mer2) // mer2 中的 y 会覆盖 mer1 中的 y
console.log('mer3:', mer3)
// concat 是 merge 的别名 ,一样的用法
// mergeWith 类似于 merge, 但是指定了 merge 的具体规则
const mer4 = mer1.mergeDeepWith((oldVal, newVal)=>{return newVal + '!!!!!'},mer2); // ()=>{} 这个参数告诉我们如果值有重复的时候我们该怎么办 ---- oldVal来自于mer1, newVal来自于mer2, 如果有重复值则返回 newVal ,但是 newVal要加上!!!!! 即返回值是 newVal!!!!!
console.log('mer4:', mer4)
// setIn 对于嵌套结构来进行设置值 setIn([层次1key, 层次2key, ...层次Nkey], value)
const deepMap = Map({
lev1: Map({
lev2: Map({
lev3: Map({
lev4: 'good'
})
})
})
})
// 在对象中嵌套赋值时:obj.lev1.lev2.lev3.lev4 = 'good morning
const setIn2 = deepMap.setIn(['lev1','lev2','lev3','lev4'],'good morning')
console.log('setIn2:', setIn2)
// 同样的嵌套层次的操作还有 deleteIn,updateIn,mergeIn ------- key变为 要赋值的value的路径
// toJS 把 map 转换成原生 object ===== 深转换
const deep = deepMap.toJS()
console.log('deep:', deep)
// toJSON 把 map 转换成原生 object ===== 浅转换
const shallow = deepMap.toJSON()
console.log('shallow:', shallow)
// toArray 把 map 转换成数组 ===== 浅转换
const arrTest = Map({
x:1,
y:2,
z:3
})
const arr = arrTest.toArray()
console.log('arr:', arr) // 转换之后是键值对的形式
// toObject 把 map 转换成原生 object ===== 浅转换
const json = arrTest.toObject()
console.log('json:', json)
// equals 判断两个 Map 对象是否相等
const map1 = Map({
x:1,
y:2,
z:3
})
const map2 = Map({
x:1,
y:2,
z:3
})
console.log('map1===map2:', map1===map2)
console.log('equals:',map1.equals(map2))
// find 查找,匹配到的第一个
const findTest = Map({
x:1,
y:2,
z:3,
username1: '张三'
})
const findResult = findTest.find((val,key) => typeof v === 'String')
console.log('findResult:', findResult)
// findLast 查找,返回最后一个符合的结果
// flatten 扁平化这个 Map // true 代表浅拉平,只拉平第一层; false 代表深拉平,拉平N层; 写数值代表拉平到第几层
const flattenTest = Map({
lev1: Map({
lev2: Map({
lev3: Map({
lev4: 'good'
}),
username:'zhangsan'
})
}),
y:2,
z:3
})
const flat2 = flattenTest.flatten(true); // ------浅
console.log('flat2:', flat2)
const flat3 = flattenTest.flatten(false); // ------深
console.log('flat3:', flat3)
// 拉平实际上就是判断是否有 value, 把有 value 的值给拉出来
// has 判断是否存在指定的 key
const hasTest = Map({
sex: 'male',
username: 'zhangsan'
})
console.log('has:', hasTest.has('username'))
// includes 判断是否存在指定的 value
const includesTest = Map({
sex: 'male',
username: 'zhangsan'
})
console.log('includes:', includesTest.includes('zhangsan'))
// 循环迭代
includesTest.forEach((val, key) => console.log('val:',val, 'key:',key))
// OrderedMap 是有序的 map,迭代输出的顺序是调用set的顺序 ----- 需要更高的开销
const Omap = OrderedMap({})
const Omap2 = Omap.set('z',1)
const Omap3 = Omap2.set('x',2)
Omap3.forEach((v,k) => console.log(k,v))
/**
* 总结:
* 1. 对应原生的对象,是无序
* 2. 循环: forEach
* 3. 如果要变为有序的Map,则使用 OrderedMap ,此时的顺序与set的顺序有关
*/