아래 코드를 보자.
let total = 0;
let item = [
{name : '새우깡', price: 100},
{name : '고래밥', price: 200},
{name : '꼬북칩', price: 300},
{name : '하이트맥주', price: 400},
];
const addItem = (name, price) => {
item.push({
name : name,
price : price
});
}
addItem('땅콩', 400);
이전 글과 같은 이유로, addItem 은 액션이다.
- 암묵적 입/출력이 존재
- 실행 시점 및 횟수에 영향을 받음
위를 "계산" 으로 바꾸려면
- 암묵적 입/출력을 명시적 입/출력으로 변경
- 실행 시점 및 횟수에 영향이 없도록 변경
이전 글 처럼, 먼저 암묵적 입/출력을 명시적 입/출력으로 바꿔보면
let total = 0;
let item = [
{name : '새우깡', price: 100},
{name : '고래밥', price: 200},
{name : '꼬북칩', price: 300},
{name : '하이트맥주', price: 400},
];
const addItemCalc = (items, name, price) => {
items.push({
name : name,
price : price
});
return items;
}
item = addItemCalc(item, '땅콩', 400);
console.log(item);
명시적 입/출력으로 변경하였다. 암묵적 입/출력 문제가 사라진 듯 하지만, 암묵적 출력 문제는 존재한다.
문제는 items 파라미터는 '참조' 로 전달이 되기 때문에, 함수 내 변경사항이 원본에 적용이 된다.
// items 파라미터는 참조로 전달된다, 즉 items 에 뭔가를 추가한다면,
// 파라미터로 전달된 원본도 같이 변경된다.
// return 값이 존재하지만, 암묵적 출력은 여전히 남아있다.
const addItemCalc = (items, name, price) => {
items.push({
name : name,
price : price
});
return items;
}
함수의 실행이, 함수 외부의 변수와 '완벽하게' 차단된다면 부수효과(side effect) 억제효과도 있고, 그만큼 테스트와 유지보수 용이성도 증가할 것이다.
해결방법 중 하나는 '복사본 리턴' 이다.
const addItemCalc = (items, name, price) => {
let result = items.slice(); //여기서 복사본을 만든다.
result.push({
name : name,
price : price
});
return result;
}
복사본을 만든 후, 배열을 변경 하고, 그 후에 변경된 배열을 리턴한다.
위와같이 구현하면, 큰 자료구조라 하더라도, 조작 시, 로직과 데이터를 완벽하게 분리 해낼 수 있다.
결론
동작을 계산으로 바꾸는 첫번째 방법 - 변경시에는 복사본을 사용하고 변경된 데이터를 리턴하라.
추가
- 객체 복사 시 성능 이슈가 있을 것이라 생각되는 분이 많을 듯 하다. 자바스크립트에서는 복사 시 기본적으로 얕은복사를 사용하고, 깊은 복사는 loadsh 등의 라이브러리를 사용하여 처리한다. 성능상의 이슈는 그리 크지 않은것으로 보이며, 필요할 경우에만 깊은 복사를 사용하면, 발생할 수 있는 성능상의 이슈를 줄일 수 있을 것이다.
'프로그래밍 > 함수형 코딩' 카테고리의 다른 글
함수형 코딩 - 2. 암묵적 입출력을 명시적 입출력으로 (0) | 2022.09.12 |
---|---|
함수형 코딩(Grokking Simplicity) - 1. 개념 (0) | 2022.09.12 |