immutable的應用

既然說到immutable,那什麼是immutable呢?

immutable Data就是一旦被創建,就不能再被更改的數據,對immutable對象的任何修改,包括增刪改查都會返回一個immutable對象,他實現的原理是Persistent Data Structure持久化數據結構,也就是使用舊數據創建新數據的時候,要保證舊數據可用且不變,同時爲了避免deepCopy把所有節點都複製一遍帶來的性能損耗,immutable使用了Structure Sharing(結構共享)即:如果對象數中一個節點發生變化,只修改這一個節點,和受它影響的父節點,其他節點進行共享;

爲什麼使用immutable呢?

使用他的具體原因:
它是一個完全獨立的庫,無論基於什麼框架都可以用它。
意義在於它彌補了 Javascript 沒有不可變數據結構的問題.
由於是不可變的,可以放心的對對象進行任意操作。
在 React 開發中,頻繁操作state對象或是 store ,配合 immutableJS 快、安全、方便
熟悉 React.js 的都應該知道, React.js 是一個 UI = f(states) 的框架,爲了解決更新的問題, React.js 使用了 virtual dom , virtual dom 通過 diff 修改 dom ,來實現高效的 dom 更新。
但是有一個問題。當 state 更新時,如果數據沒變,你也會去做 virtual dom 的 diff ,這就產生了浪費。這種情況其實很常見

this.state = {count: 0}
this.setState({count: 0});// 組件 state 並未被改變,但仍會觸發 render 方法

當然你可能會說,你可以使用 PureRenderMixin 來解決呀, PureRenderMixin 是個好東西,我們可以用它來解決一部分的上述問題
但 PureRenderMixin 只是簡單的淺比較,不使用於多層比較。那怎麼辦?自己去做複雜比較的話,性能又會非常差
方案就是使用 immutable.js 可以解決這個問題。因爲每一次 state 更新只要有數據改變,那麼 PureRenderMixin 可以立刻判斷出數據改變,可以大大提升性能

對比Object.assign

在JavaScript中,對象默認是可變的。當你複製一個對象時,JavaScript不得不復制每一個屬性來保證這兩個對象相互獨立。100,000個屬性被(淺)複製到新的對象。淺拷貝是需要時間的;
因爲當使用Object.assign,JavaScript會從舊對象(淺)複製每個屬性到新的對象。如果簡單數據的話,使用Object.assign還是沒有多大影響的,但是數據量大的時候會增加,淺拷貝的時間會增加,這樣性能上有一定的影響,這就體現出immutable的優勢。

Immutable 的幾種數據類型

List : 有序索引集,類似 JavaScript 中的 Array 。
Map : 無序索引集,類似 JavaScript 中的 Object 。
OrderedMap : 有序的 Map ,根據數據的 set() 進行排序。
Set : 沒有重複值的集合。
OrderedSet : 有序的 Set ,根據數據的 add 進行排序。
Stack : 有序集合,支持使用 unshift() 和 shift() 添加和刪除。
Range() : 返回一個 Seq.Indexed 類型的集合,這個方法有三個參數, start 表示開始值,默認值爲 0 , end 表示結束值,默認爲無窮大, step 代表每次增大的數值,默認爲 1 .如果 start = end ,則返回空集合。
Repeat() : 返回一個 vSeq.Indexe 類型的集合,這個方法有兩個參數, value 代表需要重複的值, times 代表要重複的次數,默認爲無窮大。
Record : 一個用於生成 Record 實例的類。類似於 JavaScript 的 Object ,但是隻接收特定字符串爲 key ,具有默認值。
Seq : 序列,但是可能不能由具體的數據結構支持。
Collection : 是構建所有數據結構的基類,不可以直接構建

上面那麼多常用的也就是 List 和 Map

immutable使用 :

安裝

npm i immutable --save 

方法彙總:

fromJS,set,get,setIn,getIn,without,update,updateIn,merge,mergeDeep, delete,has,hasIn…

import { fromJS,Map, List  } from 'immutable';
const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } },g:9 });
 
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } },g:9 }
 
console.log(nested2.getIn([ 'a', 'b', 'd' ]),nested2.get('a')); // 6
 
const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
 
const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
const nested5 = nested4.update('g', 10)
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } },g:10 }

const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
const map2 = Map({ c: 10, a: 20, t: 30 });
const obj = { d: 100, o: 200, g: 300 };
const map3 = map1.merge(map2, obj);
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const array = [ 7, 8, 9 ];
const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

將js對象或者數組轉變成immutable對象

import { fromJS } from 'immutable';
const initialState = fromJS({
  homeList: [],
  obj:{name: 'xixi',age:20},
  inputValue: ''
});

獲取屬性

state.get('homeList'); // 獲取store中的homeList
statae.get(['obj', 'name']); // 獲取obj組件中name

改變屬性

state.set('inputValue', action.value);  // 設置單個屬性值
// 設置多個屬性
state.merge({
  homeList: fromJS(action.value), // 由於action.value是js對象所以要轉成immutable對象
});

將immutable對象轉成js對象

state.get('homeList').toJS(); // 把todoList轉成js數組

刪除對象中的某一項,參數是對象中的key

state.delete('inputvalue')

刪除對象中的某一項

state.deleteIn("obj","name")

has() hasIn() 檢查是否有某個key

// List
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).has('0')); // true
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).hasIn([3, 'b'])); // true

// Map
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).has('a')); // true
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).hasIn(['a', 'a3'])); // true

更新對象,以及更新對象中的某一項

const nested5 = state.update('inputValue', 10)
const nested3 = state.updateIn(['obj','age'], value => value + 1);

Map.of()

console.log(Map.of('key1','value1','key2','value2','key3','value3').toJS()); // {key1: "value1", key2: "value2", key3: "value3"}

List.of()

console.log(List.of({x:1}, 2, [3], 4).toJS()); // [{x:1}, 2, [3], 4]

判斷是否是一個Map或者List
1、Map判斷
判斷是否是一個 Map , 對原生 Object 不生效

console.log(Map.isMap({})); // false
console.log(Map.isMap(Map({}))); // true

2、List判斷
判斷是否是一個 List , 對原生 Array 不生效

console.log(List.isList([])); // false
console.log(List.isList(List([]))); // true

獲取大小
1、size

// list
console.log(List([1,2,3,4]).size);// 4
console.log(List.of(1, 2, 3, 4).size);// 4
// map
console.log(Map({key: "value2", key1: "value1"}).size);// 2
console.log(Map.of({x:1}, 2, [3], 4).size);// 2
count()
// map
console.log(Immutable.fromJS({key: "value2", key1: "value1"}).count());// 4
// 可以定製條件,來確定大小
console.log(Immutable.fromJS({key: 1, key1: 34}).count((value, key, obj) => {
    return value > 3;
}));// 1 value大於3的有兩個

如有錯誤請指出,謝謝。

參考:
https://blog.csdn.net/m0_37527015/article/details/84338831
https://www.cnblogs.com/chris-oil/p/8494337.html

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