[JavaScript] Pure Function

2025. 11. 5. 17:16JavaScript

728x90

이 글에서는 JavaScript의 순수 함수(Pure Function)의 결정적 특성(Deterministic)과 참조 투명성, 부수 효과의 문제점 등을 학습 후 정리한 내용을 공유합니다.

  • 순수 함수
  • 참조 투명성
  • 부수 효과(Side-Effects)의 문제점
  • 정리
  • 회고

순수 함수 (Pure Function)

동일 입력에 동일 결과를 반환하며, 부수 효과가 없는 함수

예측 가능하도록 동작하는 결정적(Deterministic)함수로, 구성요소들이

  • 명확한 구성 요소 : 파라미터(입력), 로직(처리), 반환(출력)이 명확하게 정의되어 있어야 합니다.
  • 부수 효과 없음(No Side-Effects) : 함수 외부의 상태를 변경하지도, 외부에 의존하지도 않아야 합니다.

일반적으로 외부 상태에 의존하지 않는 결정적 동작 보장을 위해 순수함수를 사용합니다.

따라서 핵심 로직은 순수 함수로 구성하는 것이 권장됩니다.

 

 

[ 순수 함수 예시 ]

아래는 함수 add를 순수 함수인 이유입니다.

  • 결정적(Deterministic)
    : 명확한 구성 요소(매개 변수, 로직, 반환)로 구성되었으며, 매개변수 a, b에 대해 항상 동일한 결과를 제공합니다.
  • 부수 효과 없음
    : 외부 변수에 의존하지 않습니다.
function add(a, b) {
  return a + b;
}

add(10, 20); // 30
add(10, 20); // 30 결과 동일

이외에도 다음과 같은 기능들은 순수 함수로 구현될 수 있습니다.

  • 문자열 길이 계산 함수
  • 배열에서 최대값 찾기

 

[ 순수함수가 아닌 예시 ]

아래는 함수 add가 순수 함수가 아닌 이유입니다.

  • 일관성 부족 및 예측 불가능
    : 외부 변수 c에 의존하므로, 두 매개변수 a, b에 대한 결과를 예측할 수 없습니다.
  • 부수 효과 발생
    : 함수 내부에서 외부 변수 c를 수정할 수 있습니다. 이로인해 상태 변화 추적이 어려워집니다.
// 외부 상태에 의존하는 더하기 함수
let c = 10;

function add(a, b) {
    return a + b + c;
}

console.log(add(10, 12)); // 10 + 12 + 10 = 32

참조 투명성

순수 함수 호출식은 결과값과 동치이며, 호출식을 그 값으로 치환해도 프로그램 동작이 바뀌지 않는다

순수 함수는 동일 입력에 대해 항상 동일한 출력값을 반환하므로, 출력이 원시값일 경우 === 같은 값 비교에서 true가 될 수 있습니다.

function add(a, b) {
    return a + b;
}

add(1, 2) === 3 // true

부수 효과(Side-Effects)의 문제점

부수 효과는 코드 예측 가능성을 파괴하고, 높은 의존도로 인해 여러 문제를 유발합니다.

  • 디버깅의 어려움
    : 버그 발생 시 함수와 관련된 모든 외부 상태를 확인이 필요해 디버깅이 어렵습니다.
  • 코드 재사용성 저하 & 유지 보수성 저하
    : 외부 변수에 의존도가 높은 함수는 다른 환경에서 재사용이 어렵습니다.
  • 병렬 처리의 제한
    : 부수 효과가 있는 함수는 thread-safe하지 않아, 병렬 처리 시 문제가 발생할 수 있습니다.

 

[ 부수 효과 예시 : 정수 배열 정렬 ]

Array.prototype.sort()로 정수 배열 정렬 시, 기본 비교 함수는 원본 배열의 정수를 문자열로 캐스팅해 비교하며 정렬을 수행합니다.

const numbers = [3, 1, 10, 4, 2];

numbers.sort();

// 기대 결과 [1, 2, 3, 4, 10]
// 실제 결과 [1, 10, 2, 3, 4]

이를 해결하기 위해서는 별도의 비교함수를 제공해, 명확한 동작을 정의해야 합니다. 또한 .sort()는 원본 배열을 수정하는 부수효과가 발생합니다. Array.prototype.toSorted()로 새로운 복사본을 반환해 순수 함수 방식으로 처리할 수 있습니다.

 

 

[ React에서 상태 변경 시 불변성 준수 예시 ]

React에서도 상태(state) 변경 시 원본 상태 객체나 배열을 직접 수정하면 안됩니다.

복사본을 만들어 새로 교체할 때, React는 상태 변경을 감지하고 리렌더링을 하기 때문입니다.

const[items, setItems] = useState(['apple', 'banana']);

function addItem() {
		// 원본 수정하는 .push() 대신 새로운 배열 만들기
		const newItems = [...items, 'cherry'];
		setItems(newItems);
}

새로운 복사본 반환 대신, 원본 배열을 수정한다면 배열의 참조값은 변하지 않아 React는 상태 변경을 감지하지 못합니다.

결과적으로 상태를 변경해도 리렌더링이 발생하지 않습니다.


정리

  • 순수함수는 동일 입력에 동일한 결과를 반환하는 함수. 부수 효과를 발생시키지 않으면서, 예측 가능한 결정적 구성으로 이루어진 함수
  • 부수 효과는 외부 상태를 통해 코드의 예측 가능성을 파괴시켜 디버깅을 어렵게 만든다.
  • 모든 것을 순수 함수로 만들 수 없기 때문에, 최대한 순수 함수로 구성하면서도 필요할 때는 부수 효과를 유연하게 제어할 수 있어야 한다.
  • React에서는 부수 효과를 useEffect와 같은 훅(Hock)을 통해 관리하는게 필요하다.

회고

이번 학습에서 순수 함수(Pure Function)가 JavaScript 엔진이 자동으로 판별하는 대상이 아니라, 개발자가 코드에 심어 두는 설계 계약(약속)이라는 점이 가장 흥미로웠다.

JavaScript의 높은 자유도는 강점이지만, 동시에 규칙이 명시되지 않은 코드는 예측성과 안정성을 쉽게 잃는다는 뜻이기도 하다.

따라서 순수 함수의 기준을 세우고, 필요한 곳에 선택적으로 적용하는 설계 감각이 중요하다고 느꼈다.

웹 개발 실무는 본질적으로 외부와 통신(I/O, DOM, API 등)하며 의존성을 갖기 때문에 모든 로직을 순수하게 만들 수는 없다.

그럼에도 외부 환경과 분리 가능한 핵심 로직은 순수 함수로 설계하고, “입력 → 출력이 일관되고, side-effect를 남기지 않는다”는 계약을 코드로 보장하는 것이 장기적으로 더 강한 시스템을 만든다는 걸 깨달았다.

대표적으로 Array.prototype.sort가 기본 비교에서 사전식 정렬을 사용하고, 원본 배열을 직접 변경하는 부수 효과를 갖고 있음에도 표준으로 존재하는 이유는, JavaScript가 함수형 언어가 아니라 다중 패러다임 언어이기 때문이다.

즉, 메서드의 존재 자체가 순수성의 증명이 아니라, 사용자가 사용 목적에 맞게 비교 전략과 불변성 옵션을 직접 설계해야 한다는 메시지라는 것을 확인했다.

결국 중요한 건 순수 함수를 통해 언어 스펙을 무조건적으로 따라 쓰는 것이 아니라, 언어 동작의 의도를 이해하고, 설계의 이점을 취할 수 있는 부분에 순수 함수의 장점을 끼워 넣는 능력이라고 느꼈다.

이 글을 쓰며 나 스스로는 “완벽한 순수성”이 아니라, “필요한 곳에 순수성을 선언하고 통제하는 설계 능력”이 실무에서 더 현실적이고 강력하다는 결론에 도달했다.

728x90

'JavaScript' 카테고리의 다른 글

[JavaScript] 블로킹 논블로킹, 동기 비동기  (0) 2025.11.06
[JavaScript] First-Class Function  (0) 2025.11.05
[JavaScript] Function  (0) 2025.11.05
[JavaScript] namespace  (0) 2025.11.03
[JavaScript] 객체  (0) 2025.11.03