📌 클로저 개요
JavaScript에서는 다른 컴퓨터 언어와는 조금 다른 특성을 종종 가지고 있습니다. 그 중 종종 사용되는 클로저라는 개념에 대해서 알아보겠습니다.
MDN의 클로저 정의에 따르면, 다음과 같습니다.
"함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다."
여기서 주목할 만한 키워드는 "함수가 선언"된 "어휘적(lexical) 환경"입니다. 특이하게도 자바스크립트는 함수가 호출되는 환경과 별개로 기존에 선언되어 있던 환경, 즉 어휘적 환경을 기준으로 변수를 조회하려고 합니다.
이와 같은 이유로 "외부 함수의 변수에 접근할 수 있는 내부 함수"를 클로저 함수라고 합니다.
✏️ 어휘적환경(Lexical Environment) 이란? - Lexical Environment는 코드 block, function, script를 실행하기 앞서 생성되는 특별한 객체로, 실행할 스코프 범위 안에 있는 변수와 함수를 프로퍼티로 저장하는 객체다.
즉 우리가 소스 코드를 실행하면서 참조가 필요한 변수의 값을 이 Lexical Environment 라는 객체에서 식별자 이름을 키로 찾는다고 보면 된다. 이해하기 어렵다면 함수는 실행될 때 컴퓨터는 함수의 주변환경을 기억한다라고 생각하자.
📌 클로저 함수의 특징
1️⃣ 클로저 함수의 첫번째 특징 - 클로저 함수는 "함수를 리턴하는 함수" 라는 점입니다. 함수를 리턴하는 함수가 클로저의 형태를 만듭니다. 주의! - 함수를 리턴하는 함수가 다 클로저 함수는 아니다..
클로저는 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분됩니다. 클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는(closure; 폐쇄) 데에 있습니다. 따라서, 함수를 리턴하는 것만큼이나, 변수가 선언된 곳이 중요합니다.
2️⃣ 클로저 함수의 두번째 특징 - "내부 함수는 외부 함수에 선언된 변수에 접근 가능하다"라는 점입니다.
📌 클로저 함수의 장점
1️⃣ 데이터를 보존한다.
일반적인 함수는, 함수 실행이 끝나고 나면 함수 내부의 변수를 사용할 수 없습니다. 이와 다르게, 클로저는 외부 함수의 실행이 끝나더라도, 외부 함수 내 변수가 메모리 상에 저장됩니다. (어휘적 환경을 메모리에 저장하기 때문에 가능한 일입니다) 변수 add5 에는 클로저를 통해 리턴한 함수가 담겨 있습니다. add5 는 재미있게도, adder함수에서 인자로 넘긴 5라는 값을 x 변수에 계속 담은 채로 남아있습니다. 외부 함수의 실행이 끝났음에도 말이죠!
따라서 add5함수는 다음과 같이 사용할 수 있습니다. 별거 아닌 것 처럼 보이지만, 보다 실용적인 사용도 가능합니다.
다음은 클로저를 이용해 HTML 문자열을 만드는 예제입니다. 예제에서 `divMaker` 함수는 'div'라는 문자열을 `tag` 라는 변수에 담아두고 있으며, `anchorMaker` 함수는 'a'라는 문자열을 `tag`에 담아두고 있습니다.
클로저는 이처럼 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있게 해줍니다.
2️⃣ 정보의 접근 제한
다음은 '클로저 모듈 패턴'이라고 불리는 아주 유용한 패턴입니다.
위 이미지를 잘 보시면 value라는 변수에 값을 새롭게 할당할 수 있을까요?(함수를 바꾸지 않고)
답은 없습니다. 왜냐하면 '외부 스코프에서는 내부 스코프의 변수에 접근할 수 없다'라는 규칙에 의해 , 어떤 경우에도 value는 직접 수정이 불가능합니다. 그럼 어떻게 value값을 조정할까요? 리턴하는 객체가 제공하는 메서드를 통해 value값을 간접적으로 조작할 수 있습니다.
이것이 바로 정보의 접근 제한 (캡슐화) 입니다.
왜 이렇게 하는 것일까요? 만일 스코프로 value 값을 감싸지 않았더라면, value 값은 전역 변수로 선언해야 할 것입니다. 하지만 makeCounter라는 함수가 value 값을 보존하고 있기 때문에, 전역 변수로 따로 만들 필요가 없습니다.
전역변수가 좋지 않은 이유는 전역 변수는 다른 함수 혹은 로직 등에 의해 의도되지 않은 변경을 초래하거나 될 수도 있기 때문입니다. 이를 side effect라고 합니다. side effect를 최소화하면 , 의도되지 않은 변경을 줄일 수 있습니다. 따라서 이에 따른 오류로부터 보다 안전하게 값을 보호할 수 있습니다.
클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있습니다.
3️⃣ 모듈화
앞서 사용한 예제는, 단 한 개의 카운터만 만들 수 있는 것이 아닙니다. makeCounter 코드는 그대로 활용하고, 다음과 같이 실행을 해봅시다.
counter1.getValue() 의 값과 counter2.getValue()의 값은 서로에게 영향을 끼치지 않고, 각각의 값을 보존할 수 있습니다.
이와 같이 함수 재사용성을 극대화하여, 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 모듈화라고 합니다.
클로저를 통해 데이터와 메서드를 같이 묶어서 다룰 수 있습니다. 즉, 클로저는 모듈화에 유리합니다.
'코드스테이츠 > JavaScript' 카테고리의 다른 글
객체 지향 프로그래밍(OOP 4가지 개념) (0) | 2023.01.13 |
---|---|
객체지향 프로그래밍 (클래스와 인스턴스) (0) | 2023.01.13 |
Unit9-[JavaScript] 변수 선언과 스코프 (0) | 2023.01.02 |
Unit9 - [JavaScript] 스코프 (0) | 2023.01.02 |
Unit9 - [JavaScript] 원시 자료형과 참조 자료형 (0) | 2023.01.02 |