晴明的博客园 GitHub      CodePen      CodeWars     

[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)。
posted @ 2017-04-14 19:17  晴明桑  阅读(238)  评论(0编辑  收藏  举报