[js] immutable 实例
原生js
js中的对象
			let a = {};
			let b = {};
			console.log(a == b);//false
			console.log(a === b);//false
			console.log({} == {});//false
			console.log({} === {});//false
			let c = { a: 'a', b: 'b' };
			let d = { a: 'a', b: 'b' };
			console.log(c == d);//false
			console.log(c === d);//false
			console.log({ a: 'a', b: 'b' } == { a: 'a', b: 'b' });//false
			console.log({ a: 'a', b: 'b' } === { a: 'a', b: 'b' });//false
			let e = { a: 'a', b: 'b' };
			let f = e;
			console.log(e == f);//true
			console.log(e === f);//true
			e.a = 'aa';
			console.log(e == f);//true
			console.log(e === f);//true
js中的数组
			let a = [];
			let b = [];
			console.log(a == b);//false
			console.log(a === b);//false
			console.log([] == []);//false
			console.log([] === []);//false
			let c = ['a', 'b'];
			let d = ['a', 'b'];
			console.log(c == d);//false
			console.log(c === d);//false
			console.log(['a', 'b'] == ['a', 'b']);//false
			console.log(['a', 'b'] === ['a', 'b']);//false
			let e = ['a', 'b'];
			let f = e;
			console.log(e == f);//true
			console.log(e === f);//true
			e[0] = 'aa';
			console.log(e == f);//true
			console.log(e === f);//true
它们的问题在于无法比较对象/数组是否发生了变化。
immutable 与 Object.freeze、const 区别
Object.freeze 和 const 都可以达到防止对象被篡改的功能,但它们是 shallowCopy 的。对象层级一深就要特殊处理了。
is 、 equals
比较两个数据是否相等。
			let a = fromJS({ a: 1, b: 2 });
			let b = fromJS({ a: 1, b: 2 });
			console.info(a.equals(b))//true
			console.info(is(a, b))//true
// 不仅仅只能比较ImmutableJS的类型的数据
console.log(Immutable.is(undefined, undefined)); // true
console.log(Immutable.is(null, undefined)); // false
console.log(Immutable.is(null, null)); // true
console.log(Immutable.is(NaN, NaN)); // true
// 区别于 Object.is
console.log(Object.is(0, -0) ,Immutable.is(-0, 0)); // false , true
size 、count
获得数据的length。
不同于js,immutable里对象也可以获得length。
			let a = fromJS({ a: 1, b: 2 });
			let b = fromJS({ a: 1, b: 2, c: 3 });
			console.info(a.size)//2
			console.info(b.count())//3
has
		{
			let a = fromJS({ a: 1, b: 2, c: '', d: undefined });
			console.log(a.has('a'));//true
			console.log(a.has('c'));//true
			console.log(a.has('d'));//true
			console.log(a.has('e'));//false
			let b = fromJS(['a', 'b', 'c']);
			console.log(b.has(1));//true
			console.log(b.has(4));//false
		}
find
			let a = fromJS({ a: 1, b: 2, c: { d: 3, e: 4 } });
			let b = a.find((v) => {
				//return v == fromJS({ d: 3, e: 4 });//error
				//return v.equals(fromJS({ d: 3, e: 4 }));//error
				//return fromJS({ d: 3, e: 4 }).equals(v);//ok
				return is(v, fromJS({ d: 3, e: 4 }));//ok
			})
			console.info(b.toJS())//{ d: 3, e: 4 }
keySeq 、valueSeq
			let a = fromJS({ a: 1, b: 2, c: { d: 3, e: 4 } });
			console.info(a.keySeq().toJS())//["a", "b", "c"]
			console.info(a.valueSeq().toJS())//[1, 2, { d: 3, e: 4 }]
forEach 、 map
不同于js,immutable里对象也可以用forEach 、 map进行遍历。
forEach(不同于js的forEach,返回 false 会终止)。
除了forEach 、 map,还可以使用filter 、reduce 等方法,具体看文档。
		{
			let a = fromJS(['a', 'b', 'c']);
			let b = a.forEach((v) => {
				console.log(v)
			})
			//a
			//b
			//c
			console.log(b)//3
			let c = a.map((v) => {
				console.log(v)
				return v + '1';
			})
			//a
			//b
			//c
			console.log(c.toJS())//["a1", "b1", "c1"]
		}
		{
			let a = fromJS({ a: 'a2', b: 'b2', c: 'c2' });
			let b = a.forEach((v) => {
				console.log(v)
			})
			//a2
			//b2
			//c2
			console.log(b)//3
			let c = a.map((v) => {
				console.log(v)
				return v + '3';
			})
			//a2
			//b2
			//c2
			console.log(c.toJS())//{a: "a23", b: "b23", c: "c23"}
		}
get 、set 、update 、delete 、getIn 、setIn 、updateIn 、deleleIn
		{
			let a = fromJS({ a: 1, b: 2, c: '', d: undefined });
			console.log(a.get('a'));//1
			console.log(a.get('c'));//''
			console.log(a.get('d'));//undefined
			console.log(a.get('e'));//undefined
			let b = fromJS(['a', 'b', 'c']);
			console.log(b.get(1));//b
			console.log(b.get(4));//undefined
			//console.log(b.get(0).toJS());//error 一旦获取到非对象/数组数据,便不再是immutable结构
			let c = fromJS({ a: 1, b: { bb: 2, cc: 22 }, c: 3 });
			console.log(c.getIn(['b', 'bb']));//2
			console.log(c.getIn(['b', 'dd']));//undefined
			let d = c.setIn(['b', 'bb'], 4)
			console.log(d.getIn(['b', 'bb']));//4
			let e = c.updateIn(['b', 'bb'], (v) => {
				return 44;
			})
			console.log(e.getIn(['b', 'bb']));//44
			let f = fromJS({ a: 1, b: { bb: { x: { x2: 'x2', x3: 'x3' }, y: 'y1' }, cc: 22 }, c: 3 });
			let g = f.updateIn(['b', 'bb', 'x'], (v) => {
				console.info(v.toJS());//{x2: "x2", x3: "x3"}
				return v.set('x3', 'xyz');
			})
			console.info(g.getIn(['b', 'bb', 'x']).toJS());//{x2: "x2", x3: "xyz"}
			let h = f.updateIn(['b', 'bb', 'x'], (v) => {
				//return v.delete(1);//error 对象用索引不行
				return v.delete('x3');
			})
			console.info(h.getIn(['b', 'bb', 'x']).toJS())//{x2: "x2"}
			let i = f.deleteIn(['b', 'bb', 'x', 'x3']);
			console.info(i.getIn(['b', 'bb', 'x']).toJS())//{x2: "x2"}
		}
		{
			//可以创建新的键,但是不可以创建新的对象/数组
			let a = fromJS({ a: 1, b: { bb: 2, cc: 22 }, c: 3 });
			console.info(a.set('x', 4).toJS())//{ a: 1, b: { bb: 2, cc: 22 }, c: 3 ,x:4}
			console.info(a.update('y', (v) => { return 5 }).toJS())//{ a: 1, b: { bb: 2, cc: 22 }, c: 3 ,y:5}
			//a.setIn(['a', 'bb'], 4)//error
			//a.updateIn(['a', 'bb'], (v) => { return 4 })//error
			console.info(a.setIn(['b', 'bb'], 4).toJS())//{ a: 1, b: { bb: 4, cc: 22 }, c: 3 }
			console.info(a.setIn(['b', 'dd'], 4).toJS())//{ a: 1, b: { bb: 2, cc: 22,dd:4 }, c: 3 }
		}
getIn对对象使用时,([])里的参数应该为string类型.
            let a = fromJS({ 1: 'a', 2: 'b', 3: { 4: 'c', 5: 'd' } });
            console.log(a.getIn([3, 4]))//undefined
            console.log(a.getIn(['3', '4']))//c
delete
delete(index: number)
删除 index 位置的元素
超过范围/不存在的健,不会强制报错
update
update(key: K, notSetValue: V, updater: (value: V) => V): Map<K, V>
// List
const $arr1 = Immutable.fromJS([1, 2, 3]);
console.log($arr1.update('2', (value)=> {
    return value * 2;
}).toJS(), $arr1.toJS());// [1, 2, 6] [1, 2, 3]
console.log($arr1.update('6', 1, (value)=> {
    return value * 2;
}).toJS(), $arr1.toJS());// [1, 2, 3, undefined, undefined, undefined, 2] [1, 2, 3]
console.log($arr1.update('6', 0, (value)=> { // 默认值必须大于0 感觉有BUG,所以还是不要用了。
    return value * 2;
}).toJS(), $arr1.toJS());// [1, 2, 3] [1, 2, 3]
// Map
const $obj1 = Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444});
console.log($obj1.update('a', (value)=> {
    return value * 2;
}).toJS(), $obj1.toJS());// {a: 2, b: 2, c: 3, d: 444} {a: 1, b: 2, c: 3, d: 444}
console.log($obj1.update('e', 1, (value)=> {
    return value * 2;
}).toJS(), $obj1.toJS());//   {a: 1, b: 2, c: 3, d: 444, e: 2} {a: 1, b: 2, c: 3, d: 444}
console.log($obj1.update('e', 0, (value)=> { // 默认值入手是number必须大于0 感觉有BUG,所以还是不要用了。
    return value * 2;
}).toJS(), $obj1.toJS());//  {a: 1, b: 2, c: 6, d: 444} {a: 1, b: 2, c: 3, d: 444}
get getIn
只有数组可以用 number 类型 的key
get(key: number, notSetValue?: T)
// notSetValue 默认值
console.log($test.get(11, 'no have value')); // no have value
console.log($test.getIn(['2', 'a'], 'child no have value')); // 888123
console.log($test.getIn(['2', 'b'], 'child no have value')); // child no have value
list结构
React 组件 propTypes 判断是否是 List:
React.PropTypes.instanceOf(Immutable.List).isRequired
获取 List 索引的元素(负数也是能运行的):
immutableData.get(0)
immutableData.get(-1) #反向索引
console.info(fromJS(['x', 'y', 'z']).get(0));//x
通过 getIn 访问嵌套数组当中的数据:
console.info(fromJS([['x', 'xx'], 'y', 'z']).getIn([0, 1]));//xx
fromJS 与 List 、 Map的区别
fromJS可进行嵌套操作,而List 、 Map 不可以。
			let map = Map({ a: { aa: 'aa', bb: 'bb' }, b: 'b' });
			let list = List([['a', 'aa'], 'b']);
			//let map1 = map.getIn(['a', 'bb']);//error
			//console.log(map1)//error
			//let list1 = list.getIn([0, 1]);//error
			//console.log(list1)//error
			//let map2 = map.setIn(['a', 'bb'], 'xx');//error
			//console.log(map2.toJS())//error
			//let list2 = list.getIn([0, 1], 'yy');//error
			//console.log(list2.toJS())//error
			console.log(map.toJS())
			console.log(list.toJS())
合并数据
merge
注意merge的参数应为较新的数据。
对象和数组都是按照key来merge的。
- 相同结构的merge
			let map1 = fromJS({ a: 1, b: 2, c: 3 });
			let map2 = map1.set('b', 50);
			let map3 = map1.merge(map2);
			let map4 = map2.merge(map1);
			console.log(map1.get('b')); // 2
			console.log(map2.get('b')); // 50
			console.log(map1.toJS());//{a: 1, b: 2, c: 3}
			console.log(map2.toJS());//{a: 1, b: 50, c: 3}
			console.log(map3.toJS());//{a: 1, b: 50, c: 3}
			console.log(map4.toJS());//{a: 1, b: 2, c: 3}
			let list1 = fromJS(['a', 'b', 'c']);
			let list2 = list1.set(1, 'bb');
			let list3 = list1.merge(list2);
			let list4 = list2.merge(list1);
			console.log(list1.get(1)); // b
			console.log(list2.get(1)); // bb
			console.log(list1.toJS());//["a", "b", "c"]
			console.log(list2.toJS());//["a", "bb", "c"]
			console.log(list3.toJS());//["a", "bb", "c"]
			console.log(list4.toJS());//["a", "b", "c"]
- 相同结构的merge
			let map1 = fromJS({ a: 1, b: 2 });
			let map2 = fromJS({ a: 1, c: 3 });
			let map3 = map1.merge(map2);
			let map4 = map2.merge(map1);
			console.log(map1.toJS());//{a: 1, b: 2}
			console.log(map2.toJS());//{ a: 1, c: 3 }
			console.log(map3.toJS());//{a: 1, b: 2, c: 3}
			console.log(map4.toJS());//{a: 1, c: 3, b: 2}
			let list1 = fromJS(['a', 'b', 'c']);
			let list2 = fromJS(['a', 'bb']);
			let list3 = list1.merge(list2);
			let list4 = list2.merge(list1);
			console.info(list1.toJS());//["a", "b", "c"]
			console.log(list2.toJS());//['a', 'bb']
			console.log(list3.toJS());//["a", "bb", "c"]
			console.log(list4.toJS());//["a", "b", "c"]
react中的使用
  getInitialState() {
    return {
      data: Map({ times: 0 })
    }
  },
  handleAdd() {
    this.setState({ data: this.state.data.update('times', v => v + 1) });
    // 这时的 times 并不会改变
    console.log(this.state.data.get('times'));
  }
//可以简写成:
  handleAdd() {
    this.setState(({data}) => ({
      data: data.update('times', v => v + 1) })
    });
  }
数据类型
- List:有序索引集,类似于 JavaScript 中的 Array。
- Map:类似于 JavaScript 中的 Object。
- OrderedMap:有序 Map,排序依据是数据的 set() 操作。
- Set:和 ES6 中的 Set 类似,都是没有重复值的集合。
- OrderedSet:Set 的变体,可以保证遍历的顺序性。排序依据是数据的 add 操作。
- Stack:有序集合,且使用 unshift(v) 和 shift() 进行添加和删除操作的复杂度为 O(1)
- Range():返回一个 Seq.Indexed 类型的数据集合,该方法接收三个参数 (start = 1, end = infinity, step = 1),分别表示起始点、终止点和步长,如果 start 等于 end,则返回空的数据结合。
- Repeat():返回一个 Seq.indexed 类型的数据结合,该方法接收两个参数 (value,times),value 表示重复生成的值,times 表示重复生成的次数,如果没有指定 times,则表示生成的 Seq 包含无限个 value。
- Record:在表现上类似于 ES6 中的 Class,但在某些细节上还有所不同。
- Seq:序列(may not be backed by a concrete data structure)
- Iterable:可以被迭代的 (Key, Value) 键值对集合,是 Immutable.js 中其他所有集合的基类,为其他所有集合提供了 基础的 Iterable 操作函数(比如 map() 和 filter)。
- Collection:创建 Immutable 数据结构的最基础的抽象类,不能直接构造该类型。
- Iterable:可以被迭代的 (Key, Value) 键值对集合,是 Immutable.js 中其他所有集合的基类,为其他所有集合提供了 基础的 Iterable 操作函数(比如 map() 和 filter)。
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号