[譯] 利用 Immutability(不可變性)編寫更為簡潔高效的程式碼

guoyang134340發表於2019-01-19

[譯] 利用 Immutability(不可變性)編寫更為簡潔高效的程式碼

圖片來自unsplash.com

不可變性是函數語言程式設計中的一部分,它可以使你寫出更安全更簡潔的程式碼。我將會通過一些 JavaScript 的例子來告訴你如何達到不可變性。

根據維基( 地址 ):

一個不可變物件(不能被改變的物件)是指在建立之後其狀態不能被更改的物件,這與在建立之後可以被更改的可變物件(可以被改變的物件)相反。在某些情況下,一個物件的外部狀態如果從外部看來沒有變化,那麼即使它的一些內部屬性更改了,仍被視為不可變物件。

不可變的陣列

陣列是瞭解不可變性如何運作的一個很好的起點。我們來看一下。

const arrayA = [1, 2, 3];
arrayA.push(4);

const arrayB = arrayA;
arrayB.push(5);

console.log(arrayA); // [1, 2, 3, 4, 5]
console.log(arrayB); // [1, 2, 3, 4, 5]複製程式碼

例子中 arrayBarrayA 的引用,所以如果我們通過 push 方法向任意陣列中新增一個值 5,那麼就會間接影響到另外一個,這個是違反不可變性的原則的。

我們可以通過使用 slice 函式以達到不可變性,進而優化我們的例子,此時程式碼的行為是完全不一樣的。

const arrayA = [1, 2, 3];
arrayA.push(4);

const arrayB = arrayA.slice(0);
arrayB.push(5);

console.log(arrayA); // [1, 2, 3, 4]
console.log(arrayB); // [1, 2, 3, 4, 5]複製程式碼

這才是我們要的,程式碼不改變其它的值。

記住:當使用 push 來給陣列新增一個值時,你在改變這個陣列,因為這樣可能會影響程式碼裡的其他部分,所以你想要避免使變數值發生改變。slice 會返回一個複製的陣列。

函式

現在你知道了如何避免改變其它的值。那如何寫「純」的函式呢?純函式是指不會產生任何副作用,也不會改變狀態的函式。

我們來看一個示例函式,其原理與前面陣列示例的原理相同。首先我們寫一個會改變其它值的函式,然後我們將這個函式優化為「純」函式。

const add = (arrayInput, value) => {
  arrayInput.push(value);

  return arrayInput;
};複製程式碼
const array = [1, 2, 3];

console.log(add(array, 4)); // [1, 2, 3, 4]
console.log(add(array, 5)); // [1, 2, 3, 4, 5]複製程式碼

於是我們又一次改變輸入的變數的值,這使得這個函式變得不可預測。在函數語言程式設計的世界裡,有一個關於函式的鐵律:函式對於相同的輸入應當返回相同的值。

上面的函式違反了這一規則,每次我們呼叫 add 方法,它都會改變陣列變數導致結果不一樣。

讓我們來看看怎樣修改 add 函式來使其不可變。

const add = (arrayInput, value) => {
  const copiedArray = arrayInput.slice(0);
  copiedArray.push(value);

  return copiedArray;
};

const array = [1, 2, 3];複製程式碼
const resultA = add(array, 4);
console.log(resultA); // [1, 2, 3, 4]複製程式碼
const resultB = add(array, 5);
console.log(resultB); // [1, 2, 3, 5]複製程式碼

現在我們可以多次呼叫這個函式,且相同的輸入獲得相同的輸出,與預期一致。這是因為我們不再改變 array 變數。我們把這個函式叫做“純函式”。

注意: 你還可以使用 concat,來代替 slicepush
即:arrayInput.concat(value);

我們還可以使用 ES6 的擴充套件語法,來簡化函式。

const add = (arrayInput, value) => […arrayInput, value];複製程式碼

併發

NodeJS 的應用有一個叫併發的概念,併發操作是指兩個計算可以同時的進行而不用管另外的一個。如果有兩個執行緒,第二個計算不需要等待第一個完成即可開始。

[譯] 利用 Immutability(不可變性)編寫更為簡潔高效的程式碼

視覺化的併發操作

NodeJS 用事件迴圈機制使併發成為可能。事件迴圈重複接收事件,並一次觸發一個監聽該事件的處理程式。這個模型允許 NodeJS 的應用處理大規模的請求。如果你想學習更多,讀一下這篇關於事件迴圈的文章

不可變性跟併發又有什麼關係呢?由於多個操作可能會併發地改變函式的作用域的值,這將會產生不可靠的輸出和導致意想不到的結果。注意函式是否改變它作用域之外的值,因為這可能真的會很危險。

下一步

不可變性是學習函數語言程式設計過程中的一個重要概念。你可以瞭解一下由 Facebook 開發者寫的 ImmutableJS,這一個庫提供一些不可變的資料結構,比如說 MapSet、和 List

[譯] 利用 Immutability(不可變性)編寫更為簡潔高效的程式碼

點選 ? 讓更多的人可以在 Medium 上看見這篇文章,感謝閱讀。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃

相關文章