Immutable

Part01 Immutable由何而生

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

mutable

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

Deep Copy?No!

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

Part02 Immutable是個什麼

immutable

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

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

與原生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對象代理的僞實現數據結構

結構共享是指沒有改變的數據共用一個引用,這樣既減小了深拷貝的性能消耗,也減小了內存。app

extend https://reactjs.org/docs/update.htmlless

Part03 怎麼用

與React搭配使用,關鍵點是shouldComponentUpdate

熟悉 React 的都知道,React 作性能優化時有一個避免重複渲染的大招,就是使用 shouldComponentUpdate(),但它默認返回 true,即始終會執行 render() 方法,而後作 Virtual DOM 比較,並得出是否須要作真實 DOM 更新,儘管React的虛擬算法複雜度已經有了不少優化,可是在大規模組件更新時,依然會是個沒必要要的損耗。會帶來不少無必要的渲染併成爲性能瓶頸。
咱們經常使用的Purecomponent的祕密實際上是在shouldComponentUpdate中作了先後state和props的淺比較,若是不當心組件props的引用問題,這裏會致使出現不少Bug。
雖然第一層數據沒變,但引用變了,就會形成虛擬 DOM 計算的浪費。
第一層數據改變,但引用沒變,會形成不渲染,因此須要很當心的操做數據。post

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連接

相關文章
相關標籤/搜索