immutable.js使用说明

8/30/2015

我们在使用数据是,经常会将一个变量赋予另一个变量。对于复制的话,又分为深复制和浅复制。对象直接赋值的时候,往往是浅复制的过程,两个变量同时公用一个内存单元,一旦一方发生变化,另一个也会随之改变。为杜绝这种现象导致的错误,我们在本次内容将简要介绍immutable.js是如何产生不可变对象,并进行相关操作的。

不可变性存在的意义

javascript原生库中并未定义不可变性的变量数据,所以对于定义的变量经常需要去追踪数据的变化和状态的变更,防止出现意外的修改。使用Object.observe来观察数据的变更,这会导致很大的性能的开销,毕竟要调用监听器去监听数据的变化事件。所以

不可变数据就是一旦被创建之后,无法变更的数据。类似于C++中的常量数据,ES6中也有定义不可变类型let.这里我们将引入facebook的库文件:immutable.js来实现这种目的。

首先我们使用node环境来编写代码,确保环境中包含npm和node程序。

npm install immutable

安装完成后就可以调用该模块来进行相关的不可变数据的操作了。

运行实例

对象操作

产生一个不可变对象

var Immutable = require('immutable');
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
console.log(map1.get('b')); // 2
console.log(map2.get('b')); // 50

上述的例子调用了immutable的map函数产生了一个包含多个属性的不可变对象。当我们调用set函数修改其中的b属性时,由于不可变性,一个新的对象将被返回并且赋值给map2。因此当我们查看对象时获得的是不同的结果。

再来看一个比较对象的例子:

var map3 = Immutable.Map({a:1, b:2, c:3});
var map4 = map3.set('b', 2);
console.log((map3 === map4)); // no change
var map5 = map3.set('b', 50);
console.log((map3 !== map5)); // change

当我们尝试重新赋值b=2时候,由于对象并未发生改变,所以返回的还是原来的对象引用,所以两个对象仍旧是同一份内存单元,但是当b=50时候。返回的则是新的变量引用。

对于不可变对象,复制其实是生成了一个引用,而不是复制整个的对象,所以对象的比较就变成了引用的比较。这将极大的提升比较的效率,比如说在react中的diff算法中使用。

列表操作

使用列表操作与对象操作比较相似,比如在下面的列表中我们可以使用push,set unshift splice来操作不可变数组结构并返回一个修改后的数组。

var list1 = Immutable.List.of(1, 2);
var list2 = list1.push(3, 4, 5);
var list3 = list2.unshift(0);
var list4 = list1.concat(list2, list3);
assert(list1.size === 2);
assert(list2.size === 5);
assert(list3.size === 6);
assert(list4.size === 13);
assert(list4.get(0) === 1);

数据的比较

对于对象我们调用Map来产生Immutable对象属于不同的内存单元,但是我们可以利用Immutable的is函数和equals函数来进行比较内部是否具有相同的值。

var map1 = Immutable.Map({a:1, b:1, c:1});
var map2 = Immutable.Map({a:1, b:1, c:1});
assert(map1 !== map2); // false
assert(Immutable.is(map1, map2)); // true        assert(map1.equals(map2)); // 同上

####嵌套结构的调用

对于嵌套结构,我们可以调用immutable的相关函数直接的进行赋值和操作以及更新等等

var nested = Immutable.fromJS({a:{b:{c:[3,4,5]}}});
//从嵌套结构(json对象)中产生不可变对象
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }

var nested2 = nested.mergeDeep({a:{b:{d:6}}});
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
//深度复制结构数据并调用getIn获得指定的数据
nested2.getIn(['a', 'b', 'd']); // 6


var nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
//更新数据调用updateIn,注意这里使用了es6特性,需要使用相关库转换 或者改为function(x){return x+1;}

var nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }

####相关资料

  1. Github主页

  2. Facebook immutable.js文档资料


前端技术 Javascript 页面已被访问2515次

发表评论