Immutable

70次阅读

共计 2167 个字符,预计需要花费 6 分钟才能阅读完成。

Part01 Immutable 由何而生
说 immutable 之前,首先看下什么是 mutable。js 在原生创建数据类型即是 mutable,可变的。const 只是浅层次的防篡改,层级一深就没辙了。

js 在创建变量、赋值后是可变的。除了基本类型,其他的引用类型,通过变量地址来共享。改变了 obj1.a 的值,同时也会改变 obj.a 的值。其实改变的是同一个对象引用。这样共享地址来共享值的好处是节省内存,坏处是稍微不注意就会导致改 A 坏 B 的棘手问题。
Deep Copy?No!
一般的解法就是使用深拷贝而非浅拷贝,生成一份基本类型值完全相同但是没有共享地址的数据,除了浪费内存之外,深拷贝复杂引用类型时需要深度遍历,这样的做法在 React 这样频繁更新数据和对数据更新性能有要求的场景,深拷贝是一个不优雅不推荐,say no 的选择。那怎么做呢,这个时候 Immutable 就可以闪亮登场解决这个问题,为什么呢?
Part02 Immutable 是个什么

相对于 mutable,Immutable 就是在创建变量、赋值后便不可更改,若对其有任何变更, 就会回传一个新值
Immutable 只是一个定义,有各种实现,Immutable.js 就是 facebook 工程师实现 js 的 Immutable 历时三年的烧脑之作。甚至有些语言天生就是不可变数据结构,比如国内 react 的早期先驱题叶极力推崇的 ClojureScript。每次返回新值,大家可能会觉得性能也并不好啊,又占内存之类的。如果实现了结构共享,每次的新值共享内部结构以大幅减少内存占用。这意味着,如果对一个 Immutable 进行赋值 1000 次,并不会创建 1000 倍大小的内存占用数据。
与原生 JS 的 mutable 语义强烈冲突
除非从零开始一个项目,不然这种使用导致我们可能用混,第三方库也只支持原生 js 对象。我们需要采用一些手段来规避用混。

使用类型系统,TypeScript 或 Flow。消除了 Immutable 流经系统的精神负担。代价是编写风格将颠覆式的完全不同。
隐藏有关数据结构的详细信息。如果您在系统的特定部分使用 Immutable.js,请不要在其外部进行任何操作直接访问数据结构。一个很好的例子是 Redux,它是单原子 app 状态。如果 app 状态是 Immutable.js 对象,请不要强制 React 组件直接使用 Immutable.js 的 API。


真正的结构共享 vs 对象代理的伪实现
结构共享是指没有改变的数据共用一个引用,这样既减少了深拷贝的性能消耗,也减少了内存。
extend https://reactjs.org/docs/update.html
Part03 怎么用
与 React 搭配使用,关键点是 shouldComponentUpdate
熟悉 React 的都知道,React 做性能优化时有一个避免重复渲染的大招,就是使用 shouldComponentUpdate(),但它默认返回 true,即始终会执行 render() 方法,然后做 Virtual DOM 比较,并得出是否需要做真实 DOM 更新,尽管 React 的虚拟算法复杂度已经有了很多优化,但是在大规模组件更新时,依然会是个不必要的损耗。会带来很多无必要的渲染并成为性能瓶颈。我们常用的 Purecomponent 的秘密其实是在 shouldComponentUpdate 中做了前后 state 和 props 的浅比较,如果不小心组件 props 的引用问题,这里会导致出现很多 Bug。虽然第一层数据没变,但引用变了,就会造成虚拟 DOM 计算的浪费。第一层数据改变,但引用没变,会造成不渲染,所以需要很小心的操作数据。
Object.assign 可以实现不可变数据, 唯一的就是性能问题
Part04 怎么实现
seamless-immutable
Object.freeze 防止对象被修改 https://developer.mozilla.org…
function makeImmutable(obj, bannedMethods) {
// 在对象上打上 immutabilityTag 标记即表示对象不可变
addImmutabilityTag(obj);

if (process.env.NODE_ENV !== “production”) {
// 让所有导致对象改变的方法在调用时抛出错误
for (var index in bannedMethods) {
if (bannedMethods.hasOwnProperty(index)) {
banProperty(obj, bannedMethods[index]);
}
}
// 冻结对象
Object.freeze(obj);
}
return obj;
}
确保对象不可变的分三步:

打上 immutabilityTag 标记;
禁用会导致对象改变的方法;
冻结对象。

Immutable-js
精读 Immutable 结构共享 https://juejin.im/entry/59b5e…
深入探究 Immutable.js 的实现机制 https://juejin.im/post/5b9b30…
了解 Clojure 的持久变量 https://hypirion.com/musings/…
完结
(此文由 PPT 摘抄完成)PPT 链接

正文完
 0