做者簡介:hustcc 螞蟻金服·數據體驗技術團隊javascript
immutable 是什麼?不變的、一成不變的。在 Javascript 中通常指一個變量在通過一個 function 處理以後,能夠保持入參數據不變。java
舉個真實平常例子:前兩天,在業務代碼中,須要得到數據的中位數,並使用 echarts 繪製出中位線,輔助分析。寫代碼以前,先找了一下中位線的定義。react
對於有限的數集,能夠經過把全部觀察值高低排序後找出正中間的一個做爲中位數。若是觀察值有偶數個,一般取最中間的兩個數值的平均值做爲中位數。git
哦,挺簡單,因而奮筆疾書(實際上是 github 上的代碼片斷)github
/** * 求取數組中的中位數 * [1, 2, 3, 4, 4] -> 3 * [1, 2, 3, 4, 5, 6] -> 3.5 */
const calculateMedian(arr) => {
// 1. 排序
arr.sort((a, b) => a - b);
const half = Math.floor(arr.length / 2);
// 2. 按照中位數定義計算
// 奇數長度則中間值,偶數長度則中間兩個數的平均值
return arr.length % 2 !== 0 ?
arr[half] :
(arr[half - 1] + arr[half]) / 2.0;
}
複製代碼
這段代碼的問題在於函數是 mutable 的:npm
當通過函數 calculateMedian 求取數組 [5, 4, 3, 2, 1] 的中位數的時候,致使入參數組變成了 [1, 2, 3, 4, 5]。致使後續的代碼拿到的數組,都是通過排序的,數據都是混亂的。redux
上述代碼只須要修改一個地方便可:數組
const newArr = [].concat(arr).sort((a, b) => a - b);
複製代碼
其中 [].concat(arr)
達到的效果就是代碼的 immutable。數據結構
經過這樣的一個實際例子,我想應該很容易理解 mutable 代碼形成的影響是什麼?架構
不少狀況下,道理咱們都懂,可是仍是會不經意寫出 mutable 的代碼。分爲幾種狀況,看起來清晰一些吧!
不少開發者在寫代碼的時候,沒有從全局勝寒意識到函數必須保證 immutable,只在意本身的函數輸入輸出符合要求。
開發者須要有時刻警戒的意識,一旦涉及到 object 的操做,先提醒本身注意不可變。特別是對於公共模塊的開發,開源項目的開發,養成「變道就打轉向燈的好習慣」。
Array 常見的函數 push、pop、shift
等,通常都能理解它們是會修改原數組數據,是 mutable 的函數。
可是對於上述例子中的 sort
函數應該就是理解上容易產生歧義(本身以前一直覺得是生成一個新的數組,寫完這篇,我去搜索了整個業務代碼)。一樣的,容易產生歧義的函數包括:
注意:Array 中 immutable 函數不少,以上幾個函數是功能上容易誤解的。
GitHub 真是個好東西,只要你能想到的代碼,基本都有參考的,特別是 JavaScript 語言的。
可是你永遠不知道你使用的輪子是否是僅僅是一個課堂做業練手的。在使用一個開源模塊的時候,須要觀察:
在完善的單測能夠看到:
好比,若是 immutable 是項目的一個重要特性之一,那麼在單測代碼中必定會反映出來。
就像在網上購物同樣,比較懶的購物者,直接買訂單數最多的爆款。
能夠關注在 issue 處理速度、issue 中搜索關鍵字,能夠大概知道是否存在這些問題。
若是代碼簡單,能夠簡單 review 一下,抓住代碼實現的關鍵點。
既然要寫 immutable 的代碼,那咱們應該怎麼作?
針對開頭的 calculateMedian
函數,寫一個單測:
describe('calculateMedian', () => {
test('immutable', () => {
const a = [5, 4, 3, 2, 1];
const aClone = a.slice();
expect(calculateMedian(a)).toBe(3);
// 保證不能被修改!
expect(a).toEqual(aClone);
});
});
複製代碼
單測約束以後,之後其餘人修改這麼代碼致使 mutable 的時候,也會 ci 報錯的,保證這個方法的長治久安。
除此以外,開啓 Eslint 工具,也能夠對 Object 的 mutable 自動告警。
解構是 spread 語法是 ES6 中的新語法,也是我我的用的很是多的,通常代碼的 immutable 寫法,均可以知足。
好比咱們有一個用戶信息 A(幾十項信息),而後須要建立一個用戶信息 userB,除 id、name 不同以外,其餘都和 userA 一致。
const userA = {
id: 1,
name: 'hustcc',
addr: 'Hangzhou',
birth: '1992-08-01',
// ...
// 不少的數據不列出了
};
// 結構和 spread 寫法建立 userB
const userB = {
...userA,
id: 2,
name: 'ProtoTeam',
};
複製代碼
const arr = [1, 2, 3, 4, 5];
// push 操做
const arrPush = [
...arr,
6,
];
// shift 操做
const [e, ...arrShift] = arr;
// concat
const arrConcat = [...arr, ...arr];
複製代碼
在 react + redux 技術棧下,不可變數據結構是你們都提倡的作法,因此又不少框架層面的東西幫咱們處理了這些事情。
可是實際上,咱們在平時的業務代碼開發中,就須要有 immutable 的意識,善用 ES6 語法,就能夠解決咱們大部分的場景。
對咱們團隊感興趣的能夠關注專欄,關注github或者發送簡歷至'tao.qit####alibaba-inc.com'.replace('####', '@'),歡迎有志之士加入~