JavaScript 클로저 이해하기: 코드 예제와 함께 배우는 방법

작성일 :

JavaScript 클로저 이해하기: 코드 예제와 함께 배우는 방법

JavaScript를 배우다 보면 클로저라는 개념을 만나게 됩니다. 클로저는 많이 언급되지만, 초보자들에게는 자주 헷갈리는 개념 중 하나입니다. 이 글에서는 클로저의 정의, 동작 원리, 그리고 이를 실제 코드 예제로 설명하여 이해를 돕겠습니다.

클로저란 무엇인가?

클로저는 자바스크립트의 중요한 특성 중 하나로, 함수와 그 함수가 선언된 렉시컬 환경의 조합을 의미합니다. 먼저 자바스크립트의 함수 스코프와 렉시컬 스코프를 이해하는 것이 중요합니다.

함수 스코프와 렉시컬 스코프

자바스크립트는 함수 스코프를 따릅니다. 이는 변수가 함수 내에서 선언되었을 때, 그 함수 내에서만 접근 가능하다는 의미입니다. 렉시컬 스코프는 함수가 어디서 정의되었는지에 의해 결정됩니다.

예를 들어:

javascript
function outerFunction() {
    var outerVariable = 'I am outside!';

    function innerFunction() {
        console.log(outerVariable); // 'I am outside!'
    }

    innerFunction();
}

outerFunction();

이 코드에서 innerFunctionouterVariable에 접근할 수 있습니다. innerFunctionouterFunction 내에서 정의되었기 때문입니다. 이는 렉시컬 스코프 덕분입니다.

클로저의 정의

위의 예제를 조금 변형해보겠습니다:

javascript
function outerFunction() {
    var outerVariable = 'I am outside!';

    function innerFunction() {
        console.log(outerVariable);
    }

    return innerFunction;
}

var closureFunction = outerFunction();
closureFunction(); // 'I am outside!'

이 예제에서는 innerFunction을 반환하고 이를 closureFunction에 할당합니다. 놀랍게도 closureFunction을 호출하면 innerFunction이 여전히 outerVariable을 참조할 수 있습니다. 이는 클로저의 힘입니다.

클로저의 활용

클로저는 다양한 상황에서 유용하게 사용될 수 있습니다. 그 중 몇 가지 예를 살펴보겠습니다.

1. 데이터 프라이버시

클로저를 사용하여 데이터 프라이버시를 구현할 수 있습니다. 이는 변수와 함수가 외부에서 접근되지 않도록 하는 방법입니다.

javascript
function createCounter() {
    let count = 0;

    return function() {
        count++;
        return count;
    }
}

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

위의 코드에서 count 변수는 createCounter 함수 내에서만 접근 가능합니다. 이를 통해 외부에서 변경할 수 없는 프라이빗 데이터를 생성할 수 있습니다.

2. 함수 공장

클로저를 사용하면 함수 공장을 만들 수 있습니다. 이는 서로 다른 설정으로 여러 함수를 생성하는 데 유용합니다.

javascript
function greetingFactory(greeting) {
    return function(name) {
        return `${greeting}, ${name}!`;
    }
}

const sayHello = greetingFactory('Hello');
const sayHi = greetingFactory('Hi');

console.log(sayHello('Alice')); // 'Hello, Alice!'
console.log(sayHi('Bob')); // 'Hi, Bob!'

이 예제에서는 greetingFactory가 각기 다른 인사말의 함수를 생성합니다.

3. 콜백과 이벤트 핸들러

클로저는 콜백과 이벤트 핸들러에서 자주 사용됩니다. 특히 비동기 코드에서 유용합니다.

javascript
for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}

이 코드는 5개의 타이머를 설정하고 순서대로 0부터 4까지 출력을 기대하지만, 실제로는 모두 같은 값이 출력됩니다. 클로저를 사용하여 문제를 해결할 수 있습니다.

javascript
for (var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        }, i * 1000);
    })(i);
}

여기서 각 i 값이 클로저에 캡쳐되어 기대한 출력 결과를 얻을 수 있습니다.

실전 예제

추가로 클로저를 사용하여 실제로 유용한 예제를 만들어 보겠습니다. 캐싱 함수입니다:

javascript
function createCache() {
    const cache = {};

    return function(key, value) {
        if (value !== undefined) {
            cache[key] = value;
        }
        return cache[key];
    }
}

const cache = createCache();
cache('a', 100);
console.log(cache('a')); // 100
cache('b', 200);
console.log(cache('b')); // 200

이 예제에서는 값을 키로 저장할 수 있는 캐시를 생성합니다. 클로저를 사용하여 캐시 데이터를 보호하면서 접근할 수 있게 합니다.

결론

JavaScript의 클로저는 강력한 개념으로, 다양한 방식으로 활용될 수 있습니다. 클로저를 제대로 이해하면 보다 효율적이고 안전한 코드를 작성할 수 있습니다. 이 글에서 소개한 개념과 예제를 통해 클로저의 동작 원리와 그 활용 방법을 충분히 이해할 수 있기를 바랍니다.