圖片來自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]複製程式碼
例子中 arrayB 是 arrayA 的引用,所以如果我們通過 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,來代替 slice 和 push。
即:arrayInput.concat(value);
我們還可以使用 ES6 的擴充套件語法,來簡化函式。
const add = (arrayInput, value) => […arrayInput, value];複製程式碼
併發
NodeJS 的應用有一個叫併發的概念,併發操作是指兩個計算可以同時的進行而不用管另外的一個。如果有兩個執行緒,第二個計算不需要等待第一個完成即可開始。
視覺化的併發操作
NodeJS 用事件迴圈機制使併發成為可能。事件迴圈重複接收事件,並一次觸發一個監聽該事件的處理程式。這個模型允許 NodeJS 的應用處理大規模的請求。如果你想學習更多,讀一下這篇關於事件迴圈的文章。
不可變性跟併發又有什麼關係呢?由於多個操作可能會併發地改變函式的作用域的值,這將會產生不可靠的輸出和導致意想不到的結果。注意函式是否改變它作用域之外的值,因為這可能真的會很危險。
下一步
不可變性是學習函數語言程式設計過程中的一個重要概念。你可以瞭解一下由 Facebook 開發者寫的 ImmutableJS,這一個庫提供一些不可變的資料結構,比如說 Map、Set、和 List。
點選 ? 讓更多的人可以在 Medium 上看見這篇文章,感謝閱讀。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃。