본문 바로가기

Develop Log/JavaScript

JavaScript 클로저(Closure)에 대해서 알아보자!

반응형

클로저(Closure)

클로저(Closure)란

자바스크립트와 같은 일부 프로그래밍 언어에서 사용되는 중요한 개념으로 비동기 프로그래밍, 함수 팩토리, 모듈 등 다양한 고급 패턴에서 활용되고 있으며 이런 특징으로 인해 클로저는 코드의 유연성과 재사용성을 높이는 데 도움이 된다.

함수와 그 함수가 선언된 렉시컬 환경의 조합이라고 정의하고 있으며, 이 렉시컬 환경은 클로저가 생성된 위치의 스코프에 있는 변수를 포함된다.

쉽게 말한다면 클로저는 자신이 생성된 렉시컬 환경을 기억하는 함수를 말한다.

렉시컬 환경?

렉시컬 환경(Lexical Environment)은 코드를 실행하는 동안 엔진이 변수나 함수 선언, 외부 환경에 대한 정보를 관리하는 내부 데이터 구조를 말한다. "렉시컬"이라는 단어는 문법 구조와 관련된 코드가 작성된 위치를 의미하며, 이는 스코프를 결정하는 데 중요한 역할을 하게 된다.

렉시컬 환경 구성

렉시컬 환경은 두 가지 주요 컴포넌트로 구성되어 있다.

 

환경 레코드(Environment Record) : 현재 환경에서 선언된 모든 로컬 변수를 저장하는 컴포넌트이며, 함수 선언 및 현재 환경의 "this" 값에 대한 정보도 포함한다.

  • 환경 레코드는 현재 컨텍스트에서 사용할 수 있는 식별자(변수와 함수 등)를 기록하는 구조로 이루어져 있는데, 이를 통해 자바스크립트 엔진은 변수의 이름을 변수의 실제 값에 매핑하는 방법을 알게 된다. 환경 레코드는 특정 실행 컨텍스트에서 "실제로 무엇을 할 수 있는지"를 정의하게 된다.

외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference) : 외부 코드와 관련된 정보를 담은 렉시컬 환경을 가리킨다. 이를 통해 자바스크립트는 현재 환경 외부에 있는 변수에 접근할 수 있게 된다.

  • 외부 렉시컬 환경에 대한 참조는 주로 스코프 체인(scope chain)을 구현하는데 사용된다. 이는 현재 실행 중인 함수의 렉시컬 환경 외부에 존재하는 변수나 함수에 접근하기 위해 필요한 구조다.
  • 자바스크립트에서는, 함수가 선언될 때 그 함수의 스코프가 결정되는데, 이는 함수가 어떤 변수에 접근할 수 있는지 결정하는 구조로 이루어져 있다. 함수는 자신이 선언된 위치에서의 스코프(렉시컬 환경)를 기억하고 이것이 바로 '렉시컬 스코핑' 또는 '정적 스코핑'이라 불리는 원리이다.

렉시컬 환경은 실행 컨텍스트의 일부이며, 클로저에서 중요한 역할을 하고 있다. 클로저는 함수와 그 함수의 렉시컬 환경을 '기억'하는 특성을 가지고 있기 때문에 이런 특징으로 함수가 선언된 렉시컬 환경을 기억하고, 이 환경 밖에서도 해당 환경의 변수에 접근할 수 있게 해 준다. 이러한 특성은 데이터 은닉, 고차 함수 등 다양한 프로그래밍 패턴에서 사용되고 있다.

클로저의 특성

  1. 함수가 선언될 때의 렉시컬 환경을 기억한다: 클로저는 함수 내부에서 생성되는데, 이 함수는 자신이 생성될 때의 환경을 "기억"하게 된다. 이 환경은 함수가 선언될 때의 렉시컬 환경을 포함하며, 이를 통해 함수는 자신이 선언된 환경 외부에서 호출되더라도 자신이 선언될 때의 환경에 접근할 수 있다.
  2. 외부 함수보다 내부 함수가 더 오래 존속할 수 있다: 일반적으로 함수의 실행이 종료되면, 그 함수의 지역 변수는 메모리에서 제거되는데, 내부 함수가 외부 함수의 지역 변수를 참조하고 있을 경우, 이 내부 함수는 외부 함수의 지역 변수(클로저)를 계속 참조할 수 있다. 이렇게 내부 함수가 클로저를 통해 외부 함수의 변수를 참조할 수 있는 기능은 자바스크립트의 중요한 특징 중 하나로 작용한다.
  3. 상태를 저장하고 변경할 수 있다: 클로저는 자신이 생성될 때의 환경을 "기억"하기 때문에, 이를 이용해 일종의 "상태"를 저장하고 변경하는 데 사용할 수 있다. 예를 들어, 함수를 호출할 때마다 증가하는 카운터를 구현하는 데 클로저를 사용할 수 있다.
  4. 데이터 은닉과 캡슐화를 가능하게 해준다: 클로저는 외부에서 직접 접근할 수 없는 "비공개" 변수를 생성하는 데 사용할 수 있다. 이는 데이터 은닉과 캡슐화를 가능하게 하며, 이는 객체 지향 프로그래밍의 중요한 원칙 중 하나이다.
  5. 메모리 누수에 주의해야 한다: 클로저는 함수가 선언될 때의 환경을 기억하므로, 메모리를 계속 차지할 수 있다. 클로저를 사용할 때는 이러한 메모리 사용에 주의해야 하며, 불필요한 참조를 제거하지 않으면 메모리 누수가 발생할 수 있다.

코드를 통해 알아보기

function createCounter() {
  let count = 0;
  return function() {
    return ++count;
  };
}

const counter = createCounter();

console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

위 코드에서 createCounter 함수는 내부에 count라는 변수를 선언하고 있다. 이 count 변수는 createCounter 함수가 종료된 후에도 메모리에서 사라지지 않고, 내부에 선언된 익명 함수에서 계속 참조되고 있다.

이때 이 익명 함수가 바로 클로저이다. 이 클로저는 자신이 생성될 때의 렉시컬 환경, 즉 count 변수를 "기억"하고 있기 때문에, createCounter 함수가 종료된 후에도 count 변수에 접근하여 값을 변경할 수 있게 되는 것이다.

위 코드를 실행하면 counter 함수를 호출할 때마다 count 값이 1씩 증가하는 것을 확인할 수 있다. 이는 클로저가 count 변수의 상태를 계속 유지하고 있기 때문이다.

이처럼 클로저는 외부 함수의 지역 변수를 참조하고 있는 내부 함수를 의미하며, 이를 통해 자바스크립트에서 변수의 생명 주기를 제어하고 상태를 유지하는 등의 기능을 구현할 수 있다.

반응형