안녕하세요. 어느새 3편을 작성하게 됐습니다. 이번에 알아볼 개념은 클로저입니다. 아마도 '자바스크립트를 이해해보자' 편은 프로토타입, 이벤트 루프까지 작성할 예정입니다. 그 후엔 고오급 리액트 시리즈 '리액트를 이해해보자'를 작성해보려고 합니다!
개념을 알려면 단어부터 알아보아야겠죠? Closer아닙니다. Closure입니다.
영어 뜻은 '폐쇄'라는 뜻이라고 하네요. 왜 폐쇄 일까요? 추측상으론.. 폐쇄된 환경속에서 사용하는 거라고 추측됩니다.
클로저는 사실 JS에서만 사용하는 개념이 아닙니다. 함수형 프로그래밍에 이미 있던 개념이에요. (모르는 분들있더라구요 저 포함) LISP언어부터 시작된 개념으로, 내부함수가 자신이 선언될 때 어휘적 환경(Lexical Environment)을 기억하여 내부함수에서 외부함수로 접근할 수 있다는 개념입니다. 일반적으로 '함수와 어휘적 환경의 조합'이라고 표현하는데.. 말이 좀 어렵죠. 좀 쉽게 말하면 '자신이 생성될 때 주변스코프를 기억하는 함수'라고 표현해봅시다. 형태는 함수라는거죠. (모든 함수가 클로저라는건 아님)
클로저에 대해 자세하게 알아보기전에, 함수형 프로그래밍에 대해 알아봅시다. 왜 클로저란 개념을 만들었을 까요?
그림 1. 프로그래밍 패러다임
함수형 프로그래밍은 선언형 프로그래밍의 대표적인 패러다임입니다. (기존엔 명령형) 이 방식은 '어떻게(How)' 실행할지보다 '무엇(What)'을 수행할지에 중점을 둡니다. 순수 함수를 작성하고 이를 조합하여 소프트웨어를 구축하는 접근법입니다.
기존의 명령형 프로그래밍 방식에서는 프로그램 규모가 커질수록 코드가 복잡해지고 스파게티 코드가 되어 유지보수가 어려워지는 문제가 있었습니다. 이러한 한계를 극복하기 위해 함수형 프로그래밍이 발전했으며, 작고 명확한 목적을 가진 순수 함수들을 조합함으로써 코드의 가독성, 테스트 용이성 및 유지보수성을 향상시키게 됐습니다.
JavaScript는 본질적으로 함수 지향 언어입니다. 클래스가 있어서 객체지향도 가능한거 아니냐구요? 그것도 맞습니다. 근데 초기엔 없던 문법입니다. ES6부터 도입된 개념인데요, 사실 Class도 아니에요. 기존에 존재하던 프로토타입 상속을 문법만 좀 바꾼 문법적설탕에 불과하여 언어의 근본적인 함수 지향적 특성은 변하지 않았습니다.
함수형 프로그래밍의 특징을 한줄로 요악하면 다음과 같습니다.
부수 효과가 없는 순수함수를 1급객체로 간주하여 파라미터나 반환값으로 사용할 수 있으며, 참조 투명성을 지킬 수 있다.
어려운 단어들이 많죠? 중요키워드는 ['부수효과', '순수함수', '1급객체', '참조 투명성'] 정도입니다.
부수효과(Side Effect)
부수효과들은 다음과 같은 변화를 말합니다.
- 변수의 값이 변경됨
- 자료구조를 수정함
- 객체의 필드값을 설정함
- 예외나 오류가 발생하여 실행이 중단됨
- 콘솔 또는 파일 I/O가 발생
순수함수(Pure Function)
이런 부수효과를 제거한 함수를 순수함수라고 부릅니다. 함수형 프로그래밍에선 이런 순수함수들을 이용하여 코드를 작성합니다.
1급 객체(First-Class Object)
1급 객체란 다음과 같은 것이 가능한 객체를 의미합니다.
- 변수나 데이터 구조안에 담기 가능
- 파라미터로 전달 가능
- 반환값으로 사용가능
- 할당에 사용된 이름과 무관하게 고유한 구별 가능
함수형 프로그래밍에서 함수는 1급 객체로 취급받습니다. 그래서 JS에서 콜백함수같이 인자로 함수를 전달 할 수 있는거죠..!
클로저얘기를 하기 위해선 함수형 프로그래밍에 관한 선이해가 반드시 필요합니다.
클로저란 개념이 존재하기에, 함수형 프로그래밍에서 변수의 상태를 저장하기 쉬워진거죠.
그림 2. 어휘적 환경 이미지
클로저는 함수와 어휘적 환경의 조합이라고 했습니다.
여기서 어휘적 환경이 뭘까요?
이 시리즈를 1편부터 보았다면 떠오르실 겁니다.
1편에서 실행컨텍스트에 대해 분석했죠? 실행컨텍스트의 구성요소로 어휘적 환경에 대해 알아보았습니다. 어휘적 환경에 변수를 저장하게되는데, 어휘적 환경은 블록 스코프의 변수들을 저장하고 있습니다. 또한 변수저장 외에도 외부 렉시컬 환경 참조를 가지고 있어, 외부함수의 변수들에 접근할 수 있습니다. 외부 함수의 실행이 끝났어도 그 어휘적 환경은 내부 함수에 의해 참조되고 있어서 가비지 컬렉션의 대상이 되지 않아, 외부함수가 종료되어도 내부함수에서 참조를 이어갈 수 있는거죠.
클로저는 '함수와 어휘적 환경의 조합'이다.
여기서 함수는 함수형 프로그램의 함수다.
어휘적 환경은 실행 컨텍스트의 구성요소를 말하며, 어휘적 환경의 외부 렉시컬 환경 참조가 있기에, 외부함수의 변수에 접근할 수 있게 된다.