js使用函數式編程改造循環

For 循環的設計思想深受可變狀態與反作用的影響,不過函數式編程中認爲可變狀態與反作用是致使潛在錯誤與不可預測性的罪魁禍首,是應該盡力避免的模式。衆所周知,使用全局狀態會污染局部代碼,而一樣的局部狀態一樣會致使與全局狀態同樣的問題,只不過由於局部狀態的影響被限制在較小的影響範圍內,所以不像全局狀態那樣的突兀。容許可變的狀態也就意味着變量可能由於未知的緣由被改變,開發者可能要花費數小時的時間去定位究竟是哪一段代碼修改了這個變量值。在過去的開發歲月裏,我就是由於這樣變禿了,卻彷佛沒有變強。另外一方面,任何修改除了做用域內變量值的函數都被稱爲有反作用的函數。典型的譬如修改全局變量、讀入鍵盤輸入、調用遠程 API 、寫入磁盤等等。反作用的功效強大,咱們應該儘量地將其封裝與控制在必定範圍內。大道理就回顧到這裏,下面咱們直接看下代碼:編程

const cats = [ { name: 'Mojo', months: 84 }, { name: 'Mao-Mao', months: 34 }, { name: 'Waffles', months: 4 }, { name: 'Pickles', months: 6 } ]; const kittens = []; //典型的 for 循環用法 for (const i = 0; i < cats.length; i++) { if (cats[i].months < 7) { kittens.push(cats[i].name); } } console.log(kittens);

咱們改造的第一步是將 if 語句中的邏輯判斷提取出來,老實說提取以後筆者以爲正好符合Clean JavaScript:寫出整潔的 JavaScript 代碼裏面說起的讓變量名而不是註釋表述其含義的效果:函數式編程

const isKitten = cat => cat.months < 7; const kittens = []; for (const i = 0; i < cats.length; i++) { if (isKitten(cats[i])) { kittens.push(cats[i].name); } }

這種方式一方面增長了代碼的可用性,另外一方面也保證了咱們測試條件的可測試性,特別是當咱們的邏輯判斷很複雜的時候。下面咱們是將屬性提取也抽象出來:函數

const isKitten = cat => cat.months < 7; const getName = cat => cat.name; const kittens = []; for (const i = 0; i < cats.length; i++) { if (isKitten(cats[i])) { kittens.push(getName(cats[i])); } }

下面咱們能夠用函數式中的過濾與轉換函數來描述這個過程:測試

const isKitten = cat => cat.months < 7; const getName = cat => cat.name; const kittens = cats.filter(isKitten).map(getName);

到這裏咱們摒棄了push函數,即移除了可變狀態的介入。最後的重構便是將咱們的過濾與轉換過程再進行一層封裝,使其成爲可複用的過程:spa

const isKitten = cat => cat.months < 7; const getName = cat => cat.name; const getKittenNames = cats => cats.filter(isKitten).map(getName); const cats = [ { name: 'Mojo', months: 84 }, { name: 'Mao-Mao', months: 34 }, { name: 'Waffles', months: 4 }, { name: 'Pickles', months: 6 } ]; const kittens = getKittenNames(cats); console.log(kittens);
相關文章
相關標籤/搜索