本文主要整理了Immutable.js常用API的使用。
Immutable 是什么疙描?
簡(jiǎn)而言之
- Immutable數(shù)據(jù)就是一旦創(chuàng)建管行,就不能更改的數(shù)據(jù)格带。
- 每當(dāng)對(duì)Immutable對(duì)象進(jìn)行修改的時(shí)候囊蓝,就會(huì)返回一個(gè)新的Immutable對(duì)象饿悬,以此來(lái)保證數(shù)據(jù)的不可變。
因?yàn)镮mmutable的官方文檔有點(diǎn)晦澀難懂聚霜,本文只是用來(lái)整理Immutable常用的API的使用狡恬,便于使用與查詢,想了解更詳細(xì)的內(nèi)容蝎宇,請(qǐng)戳這里~
Immutable 的幾種數(shù)據(jù)類(lèi)型
-
List
: 有序索引集弟劲,類(lèi)似JavaScript中的Array。 -
Map
: 無(wú)序索引集姥芥,類(lèi)似JavaScript中的Object兔乞。 -
Set
: 沒(méi)有重復(fù)值的集合。 -
Record
: 跟普通JS對(duì)象差不多撇眯。1报嵌、只是每個(gè)key都有一個(gè)默認(rèn)值,可被覆蓋熊榛。2、當(dāng)刪除一個(gè)key時(shí)腕巡,只是將其value置為默認(rèn)值玄坦,該屬性不會(huì)從對(duì)象上刪除。3绘沉、key是固定的煎楣,一旦創(chuàng)建后就不會(huì)增加或減少。4车伞、可以通過(guò)點(diǎn)運(yùn)算來(lái)獲取對(duì)象的屬性
用的最多就是List和Map择懂,所以在這里主要介紹這兩種數(shù)據(jù)類(lèi)型的API。
API的使用
1.fromJS()
作用:將一個(gè)js數(shù)據(jù)轉(zhuǎn)換為Immutable類(lèi)型的數(shù)據(jù)另玖。
用法:fromJS(value, converter)
簡(jiǎn)介:value是要轉(zhuǎn)變的數(shù)據(jù)困曙,converter是要做的操作表伦。第二個(gè)參數(shù)可不填,默認(rèn)情況會(huì)將數(shù)組準(zhǔn)換為L(zhǎng)ist類(lèi)型慷丽,將對(duì)象轉(zhuǎn)換為Map類(lèi)型蹦哼,其余不做操作。
代碼實(shí)現(xiàn):
const obj = Immutable.fromJS({a:'123',b:'234'})
2.toJS()
作用:將一個(gè)Immutable數(shù)據(jù)轉(zhuǎn)換為JS類(lèi)型的數(shù)據(jù)要糊。
用法:immutableValue.toJS()
3.is()
作用:對(duì)兩個(gè)對(duì)象進(jìn)行比較纲熏。
用法:is(map1,map2)
簡(jiǎn)介:和js中對(duì)象的比較不同,在js中比較兩個(gè)對(duì)象比較的是地址锄俄,但是在Immutable中比較的是這個(gè)對(duì)象hashCode
和valueOf
局劲,只要兩個(gè)對(duì)象的hashCode
相等,值就是相同的奶赠,避免了深度遍歷鱼填,提高了性能。
代碼實(shí)現(xiàn):
import { Map, is } from 'immutable'
const map1 = Map({ a: 1, b: 1, c: 1 })
const map2 = Map({ a: 1, b: 1, c: 1 })
map1 === map2 //false
Object.is(map1, map2) // false
is(map1, map2) // true
4.List 和 Map
創(chuàng)建
- 直接用fromJS將原生轉(zhuǎn)成 List 或 Map
- 構(gòu)造函數(shù)List车柠、Map
const list = List([1,2,3])
const map = Map({a:1,b:2})
取值/設(shè)值/刪除/ 清空/大小 get/set/delete/clear/size (size為屬性剔氏,其他為方法)
- 用 toJS 轉(zhuǎn)原生后再操作
- get(key)
list.get(0) // 1
map.get('a') // 1
- getIn([]) 對(duì)嵌套對(duì)象或數(shù)組取值,傳參為數(shù)組竹祷,表示位置
let abs = Immutable.fromJS({a: {b:2}});
abs.getIn(['a', 'b']) // 2
abs.getIn(['a', 'c']) // 子級(jí)沒(méi)有值
let arr = Immutable.fromJS([1 ,2, 3, {a: 5}]);
arr.getIn([3, 'a']); // 5
arr.getIn([3, 'c']); // 子級(jí)沒(méi)有值
5. 使用注意點(diǎn)
1.變量命名
非常值得注意的一個(gè)點(diǎn)谈跛。因?yàn)榭赡芤昧似渌膸?kù)或者文件,使得代碼里存在immutable數(shù)據(jù)和非immutable數(shù)據(jù)。所以immutable變量需要加上 $$ 前綴來(lái)區(qū)分
2.API上的習(xí)慣
賦值操作之后要修改原數(shù)據(jù)記得要賦值塑陵。不然無(wú)法更新數(shù)據(jù)感憾。
$$data = $$data.set("hello","immutable")
3.為了性能和節(jié)省內(nèi)存, Immutable.js 會(huì)努力避免創(chuàng)建新的對(duì)象。如果沒(méi)有數(shù)據(jù)變化發(fā)生的話令花。
const { Map } = require('immutable')
const originalMap = Map({ a: 1, b: 2, c: 3 })
const updatedMap = originalMap.set('b', 2)
updatedMap === originalMap // return ture
如上代碼雖然進(jìn)行了一頓操作阻桅。然而數(shù)據(jù)并沒(méi)有改變。所以u(píng)pdatedMap和originalMap還是指向了同一個(gè)對(duì)象兼都。
const updatedMap = originalMap.set('b', 4)
updatedMap === originalMap
// return false
此時(shí)返回false
關(guān)于 React 的更新
import { is } from 'immutable';
shouldComponentUpdate: (nextProps, nextState) => {
return !(this.props === nextProps || is(Map(this.props), Map(nextProps))) ||
!(this.state === nextState || is(Map(this.state), Map(nextState)));
}
immutable 優(yōu)勢(shì)和使用場(chǎng)景
主要優(yōu)勢(shì):
1嫂沉、節(jié)省CPU
避免深拷貝,復(fù)雜對(duì)象比較
2扮碧、節(jié)省內(nèi)存
結(jié)構(gòu)共享趟章,復(fù)用已有結(jié)構(gòu)
3、lazy 操作
這段代碼的意思就是慎王,數(shù)組先取奇數(shù)蚓土,然后再對(duì)基數(shù)進(jìn)行平方操作,然后在console.log第2個(gè)數(shù)赖淤,同樣的代碼蜀漆,用immutable的seq對(duì)象來(lái)實(shí)現(xiàn),filter只執(zhí)行了3次咱旱,但原生執(zhí)行了8次确丢。??其實(shí)原理就是绷耍,用seq創(chuàng)建的對(duì)象,其實(shí)代碼塊沒(méi)有被執(zhí)行蠕嫁,只是被聲明了锨天,代碼在get(1)的時(shí)候才會(huì)實(shí)際被執(zhí)行,取到index=1的數(shù)之后剃毒,后面的就不會(huì)再執(zhí)行了病袄,所以在filter時(shí),第三次就取到了要的數(shù)赘阀,從4-8都不會(huì)再執(zhí)行??想想益缠,如果在實(shí)際業(yè)務(wù)中,數(shù)據(jù)量非常大基公,如在我們點(diǎn)餐業(yè)務(wù)中幅慌,商戶的菜單列表可能有幾百道菜,一個(gè)array的長(zhǎng)度是幾百轰豆,要操作這樣一個(gè)array胰伍,如果應(yīng)用惰性操作的特性,會(huì)節(jié)省非常多的性能
使用場(chǎng)景:
對(duì)于數(shù)據(jù)結(jié)構(gòu)復(fù)雜酸休,操作很多的使用immutable比較合適骂租。
優(yōu)勢(shì)
- 不可變對(duì)象,降低了 Mutable 帶來(lái)的復(fù)雜度
foo={a: 1};
bar=foo;
bar.a=2
// foo.a 也變?yōu)榱?
雖然這樣做可以節(jié)約內(nèi)存斑司,但當(dāng)應(yīng)用復(fù)雜后渗饮,這就造成了非常大的隱患,Mutable 帶來(lái)的優(yōu)點(diǎn)變得得不償失宿刮。為了解決這個(gè)問(wèn)題互站,一般的做法是使用 shallowCopy(淺拷貝)或 deepCopy(深拷貝)來(lái)避免被修改,但這樣做造成了 CPU (額外的拷貝操作)和內(nèi)存(拷貝所需)的浪費(fèi)僵缺。
Immutable 特點(diǎn)是:持久化數(shù)據(jù)結(jié)構(gòu) && 結(jié)構(gòu)共享
- 節(jié)省內(nèi)存
import { Map} from 'immutable';
let a = Map({
select: 'users',
filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people');
a === b; // false
a.get('filter') === b.get('filter'); // true
- 用 cusor 訪問(wèn)嵌套較深的數(shù)據(jù)
import Immutable from 'immutable';
import Cursor from 'immutable/contrib/cursor';
let data = Immutable.fromJS({ a: { b: { c: 1 } } });
// 讓 cursor 指向 { c: 1 }
let cursor = Cursor.from(data, ['a', 'b'], newData => {
// 當(dāng) cursor 或其子 cursor 執(zhí)行 update 時(shí)調(diào)用
console.log(newData);
});
cursor.get('c'); // 1
cursor = cursor.update('c', x => x + 1);
cursor.get('c'); // 2
劣勢(shì)
- 增加學(xué)習(xí)成本
- 增加資源大小 immutable.js 壓縮后16K
- 容易和原生對(duì)象混淆
React 相關(guān)
- Immutable.is
Immutable.is 比較的是兩個(gè)對(duì)象的 hashCode 或 valueOf(對(duì)于 JavaScript 對(duì)象)胡桃。由于 immutable 內(nèi)部使用了 Trie 數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ),只要兩個(gè)對(duì)象的 hashCode 相等磕潮,值就是一樣的标捺。這樣的算法避免了深度遍歷比較,性能非常好揉抵。
可使用 Immutable.is 來(lái)減少 React 重復(fù)渲染,提高性能嗤疯。當(dāng)傳遞基本數(shù)據(jù)類(lèi)型的屬性給子組件時(shí)冤今,子組件使用PureComponent即可;但是如果需要傳遞數(shù)組或?qū)ο蠼o子組件茂缚,這時(shí)就需要用到 Immutable,在子組件的shouldComponentUpdate中用Immutable.is 比較新舊對(duì)象從而減少無(wú)意義的渲染