immutability-helper 外掛的基本使用(附原始碼)
本文介紹了 immutability-helper 外掛的基本使用,詳細介紹了相關 API 的用法及注意事項。
概念
先理解一下 Immutable 的概念,Immutable資料就是一旦建立,就不能更改的資料。每當對Immutable物件進行修改的時候,就會返回一個新的Immutable物件,以此來保證資料的不可變。但是由於 Immutable 的 API 和用法學習起來比較困難,所以可以使用 immutability-helper 這個工具來對原生JS物件進行操作。本文主要是對 immutability-helper 的用法做一個講解。
原始碼
歡迎 Star!歡迎 Watch!
注意事項總結
-
immutability-helper 不會對原有物件進行修改,只是會返回一個新的物件
-
$
push、$
unshift、$
splice 的使用目標必須是陣列,否則會報錯 -
$
add、$
remove 的使用目標必須是 Set 或 Map -
其餘 API 的使用目標可以是任意資料
-
$
splice 的引數是一個運算元組,可以對目標陣列一次進行多次操作,但是引數 arrays 中的項是按順序執行的,所以使用時需要注意順序 -
任意 API 均可在多層結構內使用。可檢視擴充套件用法示例
-
可以同時執行多個 API 操作,但是請注意:多個 API 在一個語句中執行時,只會執行最後一個!!!。可檢視注意用法示例
常用 API
-
{$push: array} 同陣列的 push 方法,將引數 array 中的所有項 push 到目標陣列中
-
{$unshift: array} 同陣列的 unshift 方法,將引數 array 中的所有項 unshift 到目標陣列中
-
{$splice: array of arrays} 同陣列的 splice 方法,對於引數 arrays 中的每一項,使用該項提供的引數對目標陣列呼叫 splice()
PS: 引數 arrays 中的項是按順序應用的,所以順序很重要。在操作過程中,目標的指標可能會發生變化
-
{$set: any} 使用 any 值替換目標
-
{$toggle: array of strings} 將引數 array 中提供的下標或者屬性的值切換成相反的布林值
-
{$unset: array of strings} 從目標物件中移除引數 array 中的鍵列表
-
{$merge: object} 將引數 object 的鍵與目標合併
-
{$apply: function} 將當前值傳遞給函式並用新的返回值更新它
-
{$add: array of objects} 向 Set 或 Map 中新增值。新增到 Set 時,引數 array 為要新增的物件陣列,新增到 Map 時,引數 array 為 [key, value] 陣列
-
{$remove: array of strings} 從 Set 或 Map 中移除引數 array 中的鍵列表
API 用法及示例
初始化四個變數,之後的各種 API 操作都是基於這四個變數
const initialObject = {
name: 'Jack',
age: 22,
gender: 'Man'
};
const initialArray = ['a', 'b', 'c', 'd', 'e'];
const initialSet = new Set(['2', '0', '1', '9', '豬', '年', '快', '樂']);
const initialMap = new Map([['id', '1'], ['color', 'blue'], ['alias', 'map']]);
{$push: array}
/**
* API: {$push: array}
* 同陣列的 push 方法,將陣列 array 中包含的所有元素新增到 initialArray 的後面,作為一個新陣列返回
*/
const pushArray = update(initialArray, { $push: ['f'] });
console.log('pushArray:', pushArray); // => [ 'a', 'b', 'c', 'd', 'e', 'f' ]
{$unshift: array}
/**
* API: {$unshift: array}
* 同陣列的 unshift 方法,將陣列 ['f'] 中包含的所有元素新增到 initialArray 的前面,作為一個新陣列返回
*/
const unshiftArray = update(initialArray, { $unshift: ['f'] });
console.log('unshiftArray:', unshiftArray); // => [ 'f', 'a', 'b', 'c', 'd', 'e' ]
{$splice: array of arrays}
/**
* API: {$splice: array of arrays}
* 同陣列的 splice 方法
* 陣列 arrays 中包含的是所有需要執行的操作集合
* 元素 array 中第一個元素代表下標,第二個元素代表需要刪除的個數,第三個元素代表需要插入到 initialArray 中的的元素
*
* PS: 1、可以在 arrays 中執行多個集合;
* 2、兩個操作不是同時執行,而是按順序執行,後面的操作會在前面一個操作的執行結果上執行
*/
const spliceArray = update(initialArray, { $splice: [[1, 2], [2, 0, 'f', 'g']] });
console.log('spliceArray:', spliceArray); // => [ 'a', 'd', 'f', 'g', 'e' ]
{$set: any}
/**
* API: {$set: any}
* 可以將陣列或者物件中某一下標或者屬性的值進行替換
*/
// 將 initialArray 陣列中下標為 1 的元素修改為 'f'
const setArray = update(initialArray, { 1: { $set: 'f' } });
console.log('setArray', setArray); // => [ 'a', 'f', 'c', 'd', 'e' ]
// 將 initialObject 物件中 age 屬性值修改為 26
const setObject = update(initialObject, { age: { $set: 26 } });
console.log('setObject', setObject); // => { name: 'Jack', age: 26, gender: 'Man' }
{$toggle: array of strings}
/**
* API: {$toggle: array of strings}
* 可以將陣列或者物件中下標集合或者屬性集合的值進行切換:任何 Truthy 都會切換成 false,任何 Falsy 值都會切換成 true
*/
// 將 initialArray 中下標為 1、2 的元素值進行切換
const toggleArray = update(initialArray, { $toggle: [ 1, 2 ] });
console.log('toggleArray:', toggleArray); // => [ 'a', false, false, 'd', 'e' ]
const toggleObject = update(initialObject, { $toggle: [ 'name', 'gender' ] });
console.log('toggleObject:', toggleObject); // => { name: false, age: 22, gender: false }
{$unset: array of strings}
/**
* API: {$unset: array of strings}
* 從目標陣列或者物件中移除 array 中的下標或者屬性列表
*/
// 刪除陣列 initialArray 中下標為 1 和 2 的兩個元素,但是保留佔位
const unsetArray = update(initialArray, { $unset: [1, 2] });
console.log('unsetArray:', unsetArray.length, unsetArray); // 5 [ 'a', <2 empty items>, 'd', 'e' ]
// 刪除物件 initialObject 中 name 和 gender 屬性
const unsetObject = update(initialObject, { $unset: ['name', 'gender'] });
console.log('unsetObject', unsetObject); // unsetObject { age: 22 }
{$merge: object}
/**
* API: {$merge: object}
* 從目標陣列或者物件中合併 object 中下標或者屬性相同的元素,下標或屬性相同時 object 中的元素會替換掉目標中的元素
*/
// 將 initialArray 陣列中的 'a', 'b', 'c' 替換為 1, 2, 3
const mergeArray = update(initialArray, { $merge: [1, 2, 3] });
console.log('mergeArray:', mergeArray); // => [ 1, 2, 3, 'd', 'e' ]
// 將 initialObject 和 { name: 'Rose', gender: 'Woman', hobby: 'Swimming' } } 物件進行合併
const mergeObject = update(initialObject, { $merge: { name: 'Rose', gender: 'Woman', hobby: 'Swimming' } });
console.log('mergeObject', mergeObject); // => { name: 'Rose', age: 22, gender: 'Woman', hobby: 'Swimming' }
{$apply: function}
/**
* API: {$apply: function}
* 為目標陣列或者物件中某個下標或者屬性應用 function
*/
const apply = (val) => val + '--apply'
// 為 initialArray 陣列中下標為 1 的元素執行 apply 函式
const applyArray = update(initialArray, { 1: { $apply: apply } });
console.log('applyArray:', applyArray); // => [ 'a', 'b--apply', 'c', 'd', 'e' ]
// 為 initialObject 物件中 name 屬性執行 apply 函式
const applyObject = update(initialObject, { name: { $apply: apply } });
console.log('applyObject:', applyObject); // => { name: 'Jack--apply', age: 22, gender: 'Man' }
{$add: array of objects}
/**
* API: {$add: array of objects}
* 向 Set 中新增元素時,array 是一個物件的陣列,向 Map 中新增元素時, array 是一個 [key, value] 的陣列
*/
// 將 ['Hello', 'World'] 中的元素新增到 initialSet 後,並返回一個新的 Set
const addSet = update(initialSet, { $add: ['Hello', 'World'] });
console.log('addSet:', addSet); // => Set { '2', '0', '1', '9', '豬', '年', '快', '樂', 'Hello', 'World' }
// 將 [[3, 'Hello'], ['width', '20px']] 中的元素新增到 initialMap 中,並返回一個新的 Map
const addMap = update(initialMap, { $add: [[3, 'Hello'], ['width', '20px']] });
console.log('addMap', addMap); // => Map { 'id' => '1', 'color' => 'blue', 3 => 'Hello', 'width' => '20px' }
{$remove: array of strings}
/**
* API: {$remove: array of strings}
* 從 Set 或者 Map 中移除 array 中的鍵列表
*/
// 刪除 initialSet 中的 '豬' 和 '年' 這兩個元素
const removeSet = update(initialSet, { $remove: ['豬', '年'] });
console.log('removeSet:', removeSet); // => removeSet: Set { '2', '0', '1', '9', '快', '樂' }
// 刪除 initialMap 中的 'color'和 'alias' 對應的兩個鍵值對
const removeMap = update(initialMap, { $remove: ['color', 'alias'] });
console.log('removeMap:', removeMap); // => Map { 'id' => '1' }
擴充套件用法
- 可多層結構內使用
/**
* 擴充套件用法:可多層結構內使用
*/
const initialConfig = {
width: 100,
height: 100,
options: [
{ color: 'red', shape: 'Square' },
{ color: 'blue', shape: 'Circular' }
]
}
// 多層結構內使用
const multiConfig1 = update(initialConfig, { options: { color: { $set: 'pink' } } });
console.log('multiConfig1:', multiConfig1);
/* =>
{ width: 100,
height: 100,
options:
[ { color: 'red', shape: 'Square' },
{ color: 'blue', shape: 'Circular' },
color: 'pink' ] }
*/
注意用法
- 多種操作不要一起使用,否則只會執行最後的一個操作
/**
* 注意用法:多種操作不要一起使用,否則只會執行最後的一個操作
*/
const initialConfig = {
width: 100,
height: 100,
options: [
{ color: 'red', shape: 'Square' },
{ color: 'blue', shape: 'Circular' }
]
}
// 例子:只會執行最後的設定 color 屬性的操作
const multiConfig2 = update(initialConfig, { options: { $push: [ { color: 'deepPink', shape: 'Triangle' } ] }, options: { color: { $set: 'pink' } } });
console.log('multiConfig2:', multiConfig2);
/* =>
{ width: 100,
height: 100,
options:
[ { color: 'red', shape: 'Square' },
{ color: 'blue', shape: 'Circular' },
color: 'pink' ] }
*/