iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 10
0
Software Development

Functional Programming in JS系列 第 10

[練習] 玩轉 pure/impure function

花了鐵人賽 1/3 篇數都在講 pure function,這一篇就帶到實務來玩一下選擇題之哪些是 pure/impure function 吧

var xs = [1,2,3,4,5]

/* 1) -------*/
xs.slice(0,3) //=> [1,2,3]
xs.slice(0,3) //=> [1,2,3]
xs.slice(0,3) //=> [1,2,3]

/* 2)-------- */
xs.splice(0,3) //=> [1,2,3]
xs.splice(0,3) //=> [4,5]
xs.splice(0,3) //=> []

1 ) ✅ Pure

2 ) ❌ Impure ,xs 會改變 (mutable) 而導致 side Effect

/* 1) -------*/
const toSlug = (title) => {
    const urlFriendly = title.replace(/\W+/ig, '-')
    if(urlFriendly.length < 1) {
        throw new Error('is bad')
    }
    return urlFriendly
}

/* 2)-------- */
const toSlug = (title) => {
    return new Promise((res, rej) => {
        const urlFriendly = title.replace(/\W+/ig, '-')
 
        if(urlFriendly.length < 1) {
            rej(new Error('is bad'))
        }
        return res(urlFriendly)
    })
}

1 ) ❌ Impure , throw new Error 會有 Side Effect

2 ) ✅ Pure: return error as a value

/* 1) -------*/                                                                                                                                                                         
const signUp = (attrs, fn) => {
    return () => {
        let user = saveUser(attrs)
        fn(user)
    }
}

/* 2) -------*/                                                                                                                                                                      
const signUp = (attrs) => {
    let user = saveUser(attrs)
    welcomeUser(user)
}

1 ) ✅ Pure

2 ) ❌ Impure ,沒有回傳 return

/* 1) -------*/     
const birthday = user => {                                                                                                                                                   
    user.age += 1;                                                                                                                                                                  
    return user;                                                                                                                                                                    
}

/* 2) -------*/ 
const shout = word =>
    word.toUpperCase().concat("!")

/* 3) -------*/ 
const headerText = header_selector =>
    querySelector(header_selector).text()

/* 4) -------*/ 
const parseQuery = () =>
    location.search.substring(1).split('&').map(x => x.split('='))

/* 5) -------*/ 
var parseQueryString = function(queryString) {                           
    var params = {}, queries, temp, i, l;                                  
 
    queries = queryString.split("&");                                      
 
    for ( i = 0, l = queries.length; i < l; i++ ) {                        
        temp = queries[i].split('=');                                      
        params[temp[0]] = temp[1];                                         
    }                                                                      
 
    return params;                                                         
};

1 ) ❌ Impure: 改了 user.age

2 ) ✅ Pure

3 ) ❌ Impure : 因為他有讀取到外部,若有天外部資料不同就會有不同 output

4 ) ❌ Impure : 有用到 location.search

5 ) ✅ Pure: 雖然裡面做了很多 mutation 的事,但他還是秉持 same input, same output 原則


參考文章

如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您

歡迎追蹤我的部落格,除了技術文也會分享一些在矽谷工作的甘苦。


上一篇
Buzz word 5 : Pure Function
下一篇
Higher-order function
系列文
Functional Programming in JS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

3
良葛格
iT邦新手 2 級 ‧ 2020-09-11 08:57:57

這個範例:

const signUp = (attrs) => {
    return () => {
        let user = saveUser(attrs)
        welcomeUser(user)
    }
}

並不因為它有傳回一個函式,就令 signUp 是純函式,從 saveUserwelComeUser 來看,應該是有與外界溝通,就是有副作用。

這個範例:

var parseQueryString = function(queryString) {                           
    var params = {}, queries, temp, i, l;                                  
 
    queries = queryString.split("&");                                      
 
    for ( i = 0, l = queries.length; i < l; i++ ) {                        
        temp = queries[i].split('=');                                      
        params[temp[0]] = temp[1];                                         
    }                                                                      
 
    return params;                                                         
};

並不能說是很好的示範,因為單純只照相同輸入就有相同輸出來說,就算是 Imperative 的語言,也有很多這種例子。

確實地,在非 FP 的語言中,有很多地方會做些權衡,而有類似的作法,然而問題在於,這種作法分寸很難拿捏,因為函式內部實作,很有可能增長到數十甚至數百行以上,充滿邏輯泥塊。

在非 FP 的語言中,有很多地方會做些權衡,然而是不得已而為之,如果真的要這麼做,最好是為每個變數加上 const,至少這會強加不少限制,某些程度上可以讓函式內部實作不至於過於冗長、也可以減少邏輯泥塊的尺寸。

(為每個變數加上 const,就不會有使用迴圈的機會了,如果你在程式碼中看到迴圈,基本上就是不純的了…這時候遞迴是你的好朋友…XD)

hannahpun iT邦新手 4 級 ‧ 2020-09-11 20:46:18 檢舉

謝謝你的建議,我修改一下第一個範例,然後第二個可能我要寫一些備註會清楚一些

我要留言

立即登入留言