본문 바로가기

JS

함수형 프로그래밍 (1) - 순수함수

함수형 프로그래밍

함수형 프로그래밍은 프로그래밍 패러다임 중 하나로, 순수 함수불변성을 강조하며, 프로그램의 상태 변경을 최소화하는 것이 목표

함수형 프로그래밍은 수학적 함수의 개념에 기반을 두고 있으며, 이를 통해 코드의 간결성, 모듈성 및 예측 가능성을 높일 수 있음

 

함수형 접근방식과 명령형 접근방식의 비교

 

함수형 프로그래밍 특징

자료처리를 수학적 함수의 계산으로 표현하고 상태와 가변 데이터 대신 불변 데이터를 프로그래밍하는 패러다임

  • 순수함수
  • 불변타입
  • 일급함수와 고차함수
  • 자동메모리 관리
  • 타입 시스템 (타입 추론)
  • 커링과 함수 합성

 

객체지향 프로그래밍과 함수형 프로그래밍 비교

기본 단위 객체 (데이터 + 메서드) 함수 (순수 함수)
상태 관리 상태가 객체 내부에 저장되고 변경 가능 상태는 변경되지 않고 불변성 유지
코드 재사용 상속과 다형성을 통한 코드 재사용 가능 함수 합성고차 함수를 통한 재사용 가능
복잡성 객체와 클래스 계층이 복잡해질 수 있음 함수 조합과 불변성으로 복잡성을 줄일 수 있음
성능 객체 생성과 메서드 호출에 의존 불변성으로 인한 메모리와 성능 고려 필요
유지보수 객체 단위로 명확하게 구조화됨 함수 단위로 명확하고 예측 가능한 코드 유지 가능

 


순수함수

입력값이 같으면 출력값이 항상 같은 함수

함수가 외부 상태에 의존하지 않고 부작용이 없음을 보장

순수 함수는 코드의 예측 가능성, 테스트 용이성, 병렬 처리 및 재사용성을 높여줌

  • 부작용(side-effect) 없는 함수
  • 변경 불가한 데이터 (innutable)
    • 순수 함수는 데이터를 변경하지 않고 새로운 데이터를 반환함으로써 불변성을 유지
  • 참조 투명성 (referential transparency) == 부작용 없음
  • 느긋한 계산 : 실제 함수 호출시 그 값이 필요할 때까지 계산하지 않음

익명함수 vs 클로저

  • 클로저 closure는 람다계산식 구현체
  • 이름 없는 함수(anonymous function)로 작성가능
  • 선언된 범위의 변수를 캡처해서 저장하고 (선언적으로) 닫힘
  • 스위프트, 코틀린, JS 클로저는 캡처한 변수를 참조(reference)

클로저 (Closure)

클로저는 함수와 그 함수가 정의될 때의 렉시컬 환경(변수, 함수 등)을 캡처하여, 함수가 외부의 변수를 참조하고 사용할 수 있도록 하는 특성

클로저는 함수가 정의된 위치에서의 환경을 기억하고, 그 환경에 접근할 수 있음

function makeCounter() {
    let count = 0; // count는 외부에서 절대 접근할 수 없는 private한 값 -> makeCounter함수에서의 지역변수
    
    return function() {
        count++;
        return count;
    };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2

// makeCounter가 종료가 되어도 count값은 계속 저장되어있음

 

 

  • 상태 유지 : 클로저는 내부 함수가 외부 함수의 변수를 참조할 수 있게 하며, 이를 통해 상태를 유지할 수 있음
  • 데이터 은닉 : 클로저를 통해 외부에서 접근할 수 없는 프라이빗 상태를 구현할 수 있음
  • 모듈화 : 클로저는 코드를 모듈화하고 독립적인 기능 단위로 분리하는 데 도움을 줌
  • 비동기 작업 처리 : 클로저는 비동기 작업에서 변수를 기억하고 사용할 수 있어, 콜백 함수나 이벤트 핸들러를 작성할 때 유용

 

 

  1.  

클로저를 사용하면 안 되는 경우

  • 간단한 로직
    • 상태를 유지할 필요가 없는 간단한 로직에서는 클로저를 사용하는 것이 오히려 복잡도를 높임
    • 간단한 함수는 클로저 없이 작성하는 것이 더 좋음
  • 성능이 중요한 경우
    • 클로저는 메모리를 더 많이 사용하고, 가비지 컬렉션이 클로저를 참조하는 변수 때문에 지연될 수 있음
    • 성능이 중요한 경우 클로저 사용을 피하는 것이 좋음
  • 명확한 구조가 필요한 경우
    • 코드의 가독성과 유지보수성을 위해 명확한 구조가 필요한 경우 클로저를 과도하게 사용하면 코드가 복잡해짐