译者:边城
Immutable.js
是一个为 JavaScript 提供不可变集合的库,其灵感来源于 Clojure[脚本] 的不可变数据结构。它由 Facebook 开发。
他们在网站上解释如下:
不可变数据一旦创建就不可以更改,这使应用开发变得简单,不需要保护性复制,带来了先进的存储,以及通过简单逻辑就可以检测变化的技术。
持久化数据提供了一个可变的 API,它不会更新原有的数据,而是产生新的变更后的数据。
本文中我们会讲到在一个常见情形中,immutable.js
比javascript
会快得多:不修改原数组的情况下向数组添加元素。
在javascript
中要做这件事情,唯一的方法是先拷贝一个数组,再向其中添加元素。而immutable.js
的push
的返回一个添加了新元素的新列表;而且,这非常快。
不可变列表对决 JavaScript 数组
首先,在浏览器中加载immutable.js
:
Object.keys(Immutable)
这里有一个计算代码执行时间的benchmark
函数:
function benchmark(iterations, f) {
var start = new Date();
for (var i = 0; i < iterations; i++) {
f();
}
var end = new Date();
return ""Elapsed time: "" + (end - start) + "" msec"";
}
benchmark(1000000, function() {});
顺便提一下,你能看到javascript
函数调用机制超级快。
这个页面中所有代码片段均由klipse 插件提供对环境和交互的支持。
-
环境:代码在浏览器中执行
-
交互:你可以修改代码,它会按你的输入执行
现在我们比较一下性能:
-
创建一个
javascript
数组,与创建一个不可变列表之间的对比 -
拷贝并在
javascript
数组中插入元素,与向immutable.js
列表中插入元素的对比
创建集合
创建大小为100000
的javascipt
数组几乎不花时间:
benchmark(1, function() {
var jsArr = [];
jsArr[100000] = 42;
});
而创建大小为100000
的immutable.js
列表花了一点时间:
benchmark(1, function() {
immutableList = Immutable.Range(0,100000).toList();
})
JavaScript 数组的 slice 访求很慢
使用slice
和push
来操作javascript
数组代价很高
var jsArr = [];
jsArr[100000] = 42;
benchmark(100, function() {
jsArr.slice(0).push(43);
})
说明:
-
slice(0)
等价于拷贝整个数组 -
push
会修改调用它个方法的数组myArr = []; myArr.push(42); myArr.push(43); myArr
不可变的 push 超级快
向immutable
列表中添加元素非常快:
immutableList = Immutable.Range(0, 100000).toList();
benchmark(100, function() {
immutableList.push(43);
})
如果你看到花费的时间是0 msec
,请相信这不是一个BUG:它真地很快。增加到10倍的迭代次数来看看效果。
在我的计算机上,
immutable.js
的push
比原生javascript
的push
快约 100 倍。
注意,在往immutable.js
列表中添加元素时,列表本身并未改变。返回的是一个添加了元素的新列表:不可变集合就是这么运作的。
myList = Immutable.Range(0, 10).toList();
myList.push(42);
myList.size
深入
这里有一些有意思的文章,详细描述了一些不可变数据结构的用例和实例细节: