부수효과란 함수가 만들어진 목적과는 다른 효과 또는 부작용이다.
더 쉽게 말하면함수에 예상할 수 없는 일이 생길 가능성이 존재한다면,
이 함수는 부수 효과를 가질 수 있는 함수가 된다.
이 부수효과가 있는 함수를 비순수 함수라고 한다
// http 요청을 보내는 함수 : 순수함수 될 수 없음
const getData = () => {
axios.get('http://data.url')
.then(...)
.catch(...)
}
// 입력 내포한 함수 : 순수함수 될 수 없음
const typeInput = () => {
const input = prompt("Message");
return input;
}
// 파라미터를 직접 변경하는 함수 : 순수함수 될 수 없음
const changeParams = (arr, elem) => {
arr.push(elem);
return arr;
}
함수의 안팎에서 뭔가 예기치 않은 일이 생길 가능성이 있는 함수는 순수함수가 될 수 없다.
비동기 요청을 보내는 함수는 요청이 실패할 가능성이 있다.
입력을 포함하는 함수도 입력에 따라 출력이 달라질 가능성이 있기 때문에 순수함수가 될 수 없다.
매개변수로 들어온 값을 직접 변경하는 함수 역시 순수함수가 될 수 없다.
배열과 같은 참조 자료형 객체를 어떤 함수 안에서 직접 변경한다면,
나중에 이 객체를 인자로 받는 다른 함수의 작업에 영향을 미칠 수 있기 때문이다.
함수의 매개변수로 들어온 값을 직접 변경하는 것을 피하기만 해도, 순수함수를 만들 수 있다.
매개변수에 대한 직접 조작을 피하는 이유는 이 매개변수가 또 어디에 쓰일지 모르기 때문이다.
const num_arr = [1, 2, 3, 4, 5];
// 매개변수의 값을 직접 변경하는 불순함수
const addSixImpure = (arr) => {
// 매개변수에 직접 6 추가
arr.push(6);
return arr;
};
// 매개변수를 복사한 값을 변경하는 순수함수
const addSixPure = (arr) => {
// 펼침 연산자로 새로운 배열에 6 추가
newArr = [...arr, 6];
return newArr;
};
// 매개변수 arr에 6이 있는지 확인하는 함수
const hasSix = (arr) => {
if (arr.includes(6)) {
return true;
} else {
return false;
}
};
const new_arr = addSixImpure(num_arr);
console.log(hasSix(num_arr)); // true
addSixPure()과 addSixInpure()는 언뜻 보면 별 차이가 없어 보이지만,
addSixInpure()는 매개변수의 값을 직접 변경하는 불순함수이고, addSixPure()는 매개변수 값을 복사해서 변경하는 순수함수이다.
addSixInpure()는 num_arr을 직접 바꿨기 때문에 함수가 실행되면 num_arr의 값이 [1,2,3,4,5,6]으로 영구히 바뀐다. 그래서 hasSix()함수의 결과로는 true를 반환하게 된다.
하지만 개발자의 의도가 변수 new_arr에 addSix 함수를 호출한 새로운 배열을 할당하고 난 후, 값이 [1,2,3,4,5]인 num_arr에 대해서 6이 있는지 판단하고싶었던 거였다면 코드는 의도대로 실행되지 않는다.
의도대로라면 false가 나와야 하는데, num_arr이 이미 변경되었기 때문이다.
따라서 이런 경우에는 addSix함수가 num_arr을 직접 변경해서는 안된다.
const new_arr = addSixPure(num_arr);
console.log(hasSix(num_arr)); // false
addSixPure()는 num_arr을 직접 조작하지 않기 때문에 num_arr에 처음 할당되었던 값은 바뀌지 않는다.
따라서 hasSix(num_arr)의 결과는 false이다.
이 예시는 순수함수가 많아질수록 코드를 더 쉽게 예측할 수 있음을 알 수 있게 해준다.
addSixInpure()가 6을 num_arr에 추가해버린 부수효과 때문에 hasSix()의 결과가 부정확해졌다.
선언된 변수들을 직접 조작하지 않을수록 함수들은 부수효과 없이 개발자의 의도대로 움직일 가능성이 크다.
React state는 직접 조작을 피하는 방식으로 부수효과를 방지한다.(state, props가 변경될 때 리렌더링이 되기 때문에 의도치 않게 부수효과를 가진 함수들로 인해 불필요한 리렌더링이 잦아질 수 있다)
Redux의 reducer는 순수함수여야만 하는데, store값을 변경하는 함수가 부수효과를 동반하지 않아야 store 내부의 값들이 안전하게 보호될 수 있기 때문이다.
게다가 순수함수는 같은 입력에 대해 항상 같은 출력을 보장하니, 테스트 하기도 쉬워진다.