Immutable

Part01 Immutable由何而生

說immutable之前,首先看下什麼是mutable。js在原生創建數據類型即是mutable,可變的。
const只是淺層次的防篡改,層級一深就沒轍了。

mutable

js在創建變量、賦值後是可變的。除了基本類型,其他的引用類型,通過變量地址來共享。
改變了obj1.a的值,同時也會改變obj.a的值。其實改變的是同一個對象引用。這樣共享地址來共享值的好處是節省內存,壞處是稍微不注意就會導致改A壞B的棘手問題。

Deep Copy?No!

一般的解法就是使用深拷貝而非淺拷貝,生成一份基本類型值完全相同但是沒有共享地址的數據,除了浪費內存之外,深拷貝複雜引用類型時需要深度遍歷,這樣的做法在React這樣頻繁更新數據和對數據更新性能有要求的場景,深拷貝是一個不優雅不推薦,say no的選擇。
那怎麼做呢,這個時候Immutable就可以閃亮登場解決這個問題,爲什麼呢?

Part02 Immutable是個什麼

immutable

相對於mutable,Immutable就是在創建變量、賦值後便不可更改,若對其有任何變更,就會回傳一個新值

Immutable只是一個定義,有各種實現,Immutable.js就是facebook工程師實現js的Immutable歷時三年的燒腦之作。甚至有些語言天生就是不可變數據結構,比如國內react的早期先驅題葉極力推崇的ClojureScript。
每次返回新值,大家可能會覺得性能也並不好啊,又佔內存之類的。如果實現了結構共享,每次的新值共享內部結構以大幅減少內存佔用。這意味着,如果對一個Immutable進行賦值1000次,並不會創建1000倍大小的內存佔用數據。

與原生JS的mutable語義強烈衝突

除非從零開始一個項目,不然這種使用導致我們可能用混,第三方庫也只支持原生js對象。
我們需要採用一些手段來規避用混。

  1. 使用類型系統,TypeScript或Flow。消除了Immutable流經系統的精神負擔。代價是編寫風格將顛覆式的完全不同。
  2. 隱藏有關數據結構的詳細信息。如果您在系統的特定部分使用Immutable.js,請不要在其外部進行任何操作直接訪問數據結構。一個很好的例子是Redux,它是單原子app狀態。如果app狀態是Immutable.js對象,請不要強制React組件直接使用Immutable.js的API。

vs

https://codesandbox.io/s/yq872yrlnx

真正的結構共享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;
}

確保對象不可變的分三步:

  1. 打上immutabilityTag標記;
  2. 禁用會導致對象改變的方法;
  3. 凍結對象。

Immutable-js

精讀 Immutable 結構共享 https://juejin.im/entry/59b5e...

深入探究Immutable.js的實現機制 https://juejin.im/post/5b9b30...

瞭解Clojure的持久變量 https://hypirion.com/musings/...

完結

(此文由PPT摘抄完成)PPT鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章