• 中文
  • ENGLISH
immutable入坑指南
2018/02/08

本文作者 :冬檸

前言

今天在用 immutable 改寫以前的舊代碼。數據的嵌套結構有可能很深的情況, 內部對于數據的增刪改查和各種循環遞歸操作有很多。用了 immutable.js (其實也配合使用了TypeScript,效果更佳) 來改造了下。一個總結體驗那就是~

immutable初相識

immutable 的英文意思是“不可變的”。從名字就已經體現出 immutable.js 的精髓了。在immutable的世界觀里, 一切都是不可變的數據。對 Immutable 數據的修改會返回一個新的 Immutable 對象。
而傳統的Js里十分讓人頭疼的一點就是對象的數據傳遞是引用傳遞, 更新了新的對象也會影響原有的對象。從而使用各種 deepExtend, deepCopy方法來解決這個問題。而使用immutable.js就沒有這個煩惱。
舉個栗子:

let obj1 = Immutable.Map({ a: 1, b: 2, c: 3 })
let obj2 = obj1
obj2 === obj1
// return true(此時obj2實例和obj1實例指向了同一個地址)
obj2 = obj2.set("b",4)
// 此時obj2已經被更新,指向了另一個地址
obj2 === obj1
// return false
// 改變obj2并不影響obj1

常用的概念和操作

常用的對象

  1. Map: 鍵值對結構,通常對應js中的object結構轉換過來的類型。但是和js的object的很多特性有明顯的區分。
    Object只接受字符串作為鍵名,然而Map接受任何類型的數據作為鍵名。
let obj = { 1: "one" }
Object.keys(obj) // [ "1" ]
console.log(obj["1"], obj[1]) // "one","one"
let map = Map(obj)
console.log(map.get("1"), map.get(1)) // "one", undefined

Map支持鍵值對的遍歷(map,forEach,filter)等操作。大大方便了js中Object.keys()來遍歷對象的寫法
2. OrderedMap: 一種有序的Map類型。彌補了Object對象無序的缺憾。
3. List: 有序列表, 對應js中的Array
4. Set: 不可重復的列表

常用的操作

1.和js數據類型相互轉化
  • Immutable.Map({}) 對象換成Map
  • Immutable.List([]) 數組換成List
  • Immutable.formJS()
  • 識別傳入的數據并自動轉換成相應Map | List類型
  • 對于Immutable對象, 有 toJS(), toJSON(), toArray(), toObject()方法轉換成相應的原生Js結構。
2.判斷兩個對象的值是否相等
let obj1 = Immutable.Map({ a: 1, b: 2, c: 3 })
let obj2 = Immutable.Map({ a: 1, b: 2, c: 3 })
Immutable.is(obj1, obj2); // or obj1.equals(obj2)
// return ture

3.深度取值
let map1 = Immutable.Map({ a: {d: { target : 1}}, b: 2, c: 3 })
const target = Immutable.getIn(map1, ["a","d","target"])
// target: 1

4.深度賦值

有一個cursor(游標)的概念, 可以進行深度賦值的操作。但會在下一個版本即將被廢棄。建議使用setIn來代替。

let map1 = Immutable.Map({ a: {d: { target : 1}}, b: 2, c: 3 })
map1 = Immutable.setIn(map1, ["a","d","target"], 4)
// map1: { a: {d: { target : 4}}, b: 2, c: 3 }

5.淺合并(類似于Object.assign, 只合并了第一層)
const map1 = Immutable.Map({ a: {d: { target : 1}}});
const map2 = Immutable.Map({ a: {c: 1}});
const map3 = Immutable.merge(map1,map2)
console.log(map3.toJS())
// { a: {c: 1}}

6.深度合并
const map1 = Immutable.Map({ a: {d: { target : 1}}});
const map2 = Immutable.Map({ a: {c: 1}});
const map3 = Immutable.mergeDeep(map1,map2)
console.log(map3.toJS())
// { a: {c: 1, d: { target : 1}}}}

優勢

1.節省內存

  • 使用了Trie數據結構來進行儲存。使用了結構共享,即如果對象樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享。
    比如對象
const data = {
to: 7,
tea: 3,
ted: 4,
ten: 12,
A: 15,
i: 11,
in: 5,
inn: 9
}

根據trie結構,存儲的結構類似于

如果更改了了tea字段 3 -\> 14,那么只需改變四個節點,來更新形成新的樹, 這就是結構共享。

2.提升計算性能

使用了 Trie數據結構。避免深度比較。如果兩個對象的值相等。那么他們的hashCode也相等。從而比較hashCode即可比較兩個對象的值是否相等,避免了深度比較。

3.擁抱函數式編程

4.使用便利

  • 因為數據是不可變的。同時提供的API面向開發者也十分友好。

使用immutable的注意事項

1.變量命名

非常值得注意的一個點。因為可能引用了其他的庫或者文件,使得代碼里存在immutable數據和非immutable數據。所以immutable變量需要加上 $$ 前綴來區分

2.API上的習慣

賦值操作之后要修改原數據記得要賦值。不然無法更新數據。
$$data = $$data.set("hello","immutable")

3.無法使用function傳值來修改數據

let $$data = Map({hello: "immutable"});
function changeData($$data){
$$data = $$data.set("hello","world")
}
changeData($$data)
console.log($$data.toJS())
// {hello: "immutable"}

如上, $$data并不會改變。所以在寫改變數據的方法的時候需要返回新值。然后覆蓋舊值。

let $$data = Map({hello: "immutable"});
function changeData($$data){
return $$data.set("hello","world")
}
$$data = changeData($$data)
console.log($$data.toJS())
// {hello: "world"}

4.為了性能和節省內存, Immutable.js 會努力避免創建新的對象。如果沒有數據變化發生的話。

const { Map } = require('immutable')
const originalMap = Map({ a: 1, b: 2, c: 3 })
const updatedMap = originalMap.set('b', 2)
updatedMap === originalMap // return ture

如上代碼雖然進行了一頓操作。然而數據并沒有改變。所以updatedMap和originalMap還是指向了同一個對象。

const updatedMap = originalMap.set('b', 4)
updatedMap === originalMap
// return false

此時返回false

5.Immutable的使用場景

雖然immutable有種種好處, 但并不是在所有場景都建議使用Immutable, 對于數據結構復雜,操作很多的使用immutable比較合適。但對于簡單的應用場景, 還是使用原生的js吧。

文章參考

訂閱我們
体彩20选5开奖结果查询 库存布怎么赚钱 微信赚钱能退回吗 梦幻西游109大唐单开赚钱 快播彩票首页 个人插画师怎么赚钱 路边摊麻辣烫能赚钱吗 云禾农场怎么赚钱 图书公司赚钱 新生彩票网址 西安租个车跑滴滴能赚钱吗 tiny farm 前期怎么赚钱 24小时上下分麻将电玩 加盟吉野家能赚钱吗 2018年做什么买卖赚钱 博猫娱乐苹果 大唐天下 赚钱模式