우선 순수 함수
에 대해 설명을 해야합니다. 순수 함수(pure function)
이란 함수형 프로그래밍
에서 사용되는 언어로 함수가 수행하는 기능 외에 다른 효과가 나타나지 않는 것을 의미(부작용이 없다)합니다. 순수 함수가 아니고 기능 외에 다른 효과가 나타나는 함수를 불순 함수(impure function)
이라고 부릅니다.
불순 함수는 순수 함수로 만드는 조건에 부합하게 재작성하면 순수 함수로 만들 수 있으며, 순수 함수의 조건
에는 다음과 같은 조건들이 있습니다.
다음과 같이 매개변수로 배열을 받아서 push를 통해 배열을 변경(= 매개변수를 변경)하는 것은 불순 함수의 대표적인 예시입니다.
let arr: number[] = [1, 2, 3];
const pushArr = (arr: number[]): number[] => {
arr.push(4);
return arr;
}
pushArr(arr);
console.log(arr);
타입스크립트에서는 함수형 프로그래밍을 위해 순수 함수를 구현하기 쉽도록 readonly
라는 키워드를 지원하고있습니다. 사용 방법은 변하면 안되는 매개변수 타입 앞에 readonly
키워드를 붙이기만 하면 됩니다. 이렇게 붙인 매개변수는 함수 내부에서 변경을 감지하면 오류를 띄워줍니다.
let arr: number[] = [1, 2, 3];
const pushArr = (arr: readonly number[]): number[] => {
arr.push(4); //매개변수로 받은 배열을 변화시키므로 에러!
return arr;
}
pushArr(arr);
console.log(arr);
순수 함수를 유지하는 것이 좋고, 그에 필요한 키워드도 알았는데 그러면 순수 함수 내부에서 배열의 가공은 어떻게 할까요?
우선 복사란 어떤 변수값을 다른 변수값으로 설정하는 것을 의미합니다.
let a = 4;
let b = a;
얕은 복사(shallow-copy)
는 변수(객체 등)은 별도의 존재로 생성하지만, 그 안의 내용은 동일한 것을 의미합니다. 다음 코드는 얕은 복사의 예제입니다.
let arr: number[] = [1, 2, 3];
let copiedArr: number[] = arr;
copiedArr.push(4);
console.log(arr);
console.log(copiedArr);
복사한 변수에 push를 통해 값을 조작했지만, 원본인 arr도 값이 변했음을 알 수 있습니다.
반대로 깊은 복사(deep-copy)
는 변수(객체 등)을 별도로 생성하고, 그안의 정보나 로직 등도 별도로 생성하는 것을 의미합니다. 다음 코드는 깊은 복사의 예제입니다.
let a: number = 4;
let b: number = a;
b += 1;
console.log(a);
console.log(b);
복사한 변수에 1을 더한 것이 기존 변수에 어떠한 영향도 미치지 않았습니다. 이는 깊은 복사로 인해 값과 로직이 동일한 별개의 변수로 복사되었기 때문입니다.
그럼 순수 함수에서 배열을 가공하기 위에서는 원본(매개변수로 전달 된 배열)을 깊은 복사
로 복사해서 이용하는 것이 좋다는 것을 우리는 알 수 있습니다.
배열의 깊은 복사를 위해서는 전개 연산자 ...
를 이용합니다.
let arr: number[] = [1, 2, 3];
let copiedArr: number[] =[ ...arr];
copiedArr.push(4);
console.log(arr);
console.log(copiedArr);
전개 연산자의 깊은 복사 덕분에 기존 배열은 기존 배열대로, 복사본은 본사본 대로 동작합니다. 이런 점을 이용해서 우리는 순수 함수 내부에서 배열을 사용할 땐 전개 연산자를 이용한 깊은 복사를 하고, 깊은 복사된 배열을 기존 배열을 사용하듯이 이용 할 수 있다는 것을 알게 되었습니다.
또한 배열의 정제와 가공을 담당하는 filter와 map 메소드도 깊은 복사를 기반으로 진행되기 때문에 순수 함수 내부에서 사용 가능한 메소드입니다.