자바스크립트의 클로저

자바스크립트의 클로저

이 기사에서는 자바스크립트의 클로저에 대해 설명합니다.

YouTube Video

자바스크립트의 클로저

자바스크립트에서 '클로저'는 매우 중요하고 강력한 개념 중 하나입니다. 클로저를 이해함으로써 함수의 동작과 스코프, 자바스크립트의 비동기 처리 및 이벤트 처리와 같은 다양한 상황에서 유용한 지식을 얻을 수 있습니다. 여기에서 클로저의 기본 정의부터 구체적인 예제 및 활용 방법까지 모든 것을 자세히 설명하겠습니다.

클로저란 무엇인가?

클로저는 함수가 생성된 스코프 밖에서 호출되더라도 해당 스코프 내의 변수에 접근할 수 있는 메커니즘을 의미합니다. 클로저를 활용하면 함수가 외부 변수를 지속적으로 '기억'할 수 있게 됩니다.

클로저는 다음 두 가지 요소로 구성됩니다.

  1. 함수 정의 (함수 자체)

  2. 함수가 정의된 스코프 (함수 외부의 변수와 다른 함수들)

자바스크립트에서 클로저는 함수가 생성된 스코프 내의 변수에 접근할 수 있는 능력을 가지고 있기 때문에 가능합니다.

기본 예제

먼저, 클로저의 기본 예제를 살펴보겠습니다. 다음 코드에서 outerFunctioninnerFunction이라는 함수를 반환합니다. 중요한 점은 innerFunctionouterFunction 스코프 내에서 정의된 변수 count에 접근할 수 있다는 것입니다.

 1function outerFunction() {
 2    let count = 0;
 3
 4    function innerFunction() {
 5        count++;
 6        console.log(`Current count: ${count}`);
 7    }
 8
 9    return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3

클로저의 작동 원리

위 예제에서 보듯이, outerFunction이 실행된 후에도 countinnerFunction에 의해 유지됩니다. innerFunction은 계속해서 outerFunction의 스코프에 접근할 수 있으며, 따라서 countinnerFunction 내에서 업데이트됩니다. 이것이 클로저의 기본 작동 메커니즘입니다.

innerFunctioncounter 변수에 할당되며, outerFunction이 이미 실행을 완료했음에도 불구하고 count의 상태가 유지되는 것을 알 수 있습니다. 이는 자바스크립트가 함수 정의 시점의 스코프를 지속적으로 '기억'하기 때문입니다.

응용: 클로저를 활용한 프라이빗 변수

클로저는 객체 지향 프로그래밍에서 '프라이빗 변수'처럼 사용할 수 있습니다. 일반적으로 JavaScript에서는 객체 속성이 외부에서 직접 접근 가능하지만, 클로저를 사용하면 함수 범위 내 변수의 외부 직접 조작을 방지할 수 있습니다.

다음 예제에서는 createCounter 함수가 클로저를 사용하여 카운터를 생성하고 프라이빗 변수 count를 가진 카운터를 반환합니다.

 1function createCounter() {
 2    let count = 0;
 3
 4    return {
 5        increment: function() {
 6            count++;
 7            console.log(`Count: ${count}`);
 8        },
 9        decrement: function() {
10            count--;
11            console.log(`Count: ${count}`);
12        },
13        getCount: function() {
14            return count;
15        }
16    };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1

이 예제에서 countcreateCounter 함수의 스코프 내에 있으므로 외부에서 직접 접근할 수 없습니다. 그러나 이는 incrementdecrement 메서드를 통해 조작할 수 있습니다. 이와 같이 클로저를 사용하면 JavaScript에서 프라이빗 변수의 개념을 도입할 수 있습니다.

클로저의 실용적인 예

콜백 함수와의 조합

클로저는 비동기 처리를 관리하기 위해 콜백 함수와 함께 자주 사용됩니다. 예를 들어 타이머를 사용하는 예제를 살펴보겠습니다.

 1function startTimer(duration) {
 2    let timeLeft = duration;
 3
 4    function countdown() {
 5        console.log(`Time left: ${timeLeft} seconds`);
 6        timeLeft--;
 7
 8        if (timeLeft >= 0) {
 9            setTimeout(countdown, 1000);
10        }
11    }
12
13    countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds

이 예제에서 countdown 함수는 startTimer 스코프 내부의 timeLeft 변수에 접근합니다. 이와 같이 클로저는 시간이 지나도 변수의 상태를 유지하기 때문에 타이머와 같은 비동기 처리에 매우 유용합니다.

이벤트 핸들러

클로저는 이벤트 핸들러를 설정할 때도 편리합니다. 다음 예제에서는 버튼 클릭 횟수를 기록하기 위해 클로저가 사용됩니다.

 1function setupClickCounter(buttonId) {
 2    let clickCount = 0;
 3
 4    const button = document.getElementById(buttonId);
 5    button.addEventListener('click', function() {
 6        clickCount++;
 7        console.log(`Button clicked ${clickCount} times`);
 8    });
 9}
10
11setupClickCounter('myButton');

이 경우 clickCount는 클릭할 때마다 증가하며 값이 유지됩니다. 클로저를 사용하여 각 버튼에 독립적인 카운터를 할당할 수 있습니다.

결론

클로저는 JavaScript의 유연성과 강력함을 상징하는 개념입니다. 클로저는 함수 스코프 내의 변수를 포함하며, 외부에서 접근 가능한 함수를 통해 해당 변수에 작업을 수행할 수 있도록 합니다. 이 메커니즘을 이해하고 활용함으로써 JavaScript 코딩에서 더욱 고급 기술을 습득할 수 있습니다.

클로저는 이벤트 처리 및 비동기 처리에서 객체 지향 프로그래밍의 유사 구현에 이르기까지 다양한 상황에 적용됩니다.

위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.

YouTube Video