클로저(Closure) - 자바스크립트에서 동작하는 방식

sujin·4일 전
0

자바스크립트

목록 보기
12/12
post-thumbnail

최근 면접 준비 하면서 자바스크립트의 개념에 대해서 다시 살펴보고 있는데요. 면접 단골 질문이기도 하면서 자바스크립트의 동작 방식을 이해하기 위해서 필수로 알아야할 클로저에 대해서 정리해보려고 합니다~!


1️⃣ 클로저란?

클로저는 주변 상태(어휘적 환경)에 대한 참조와 함께 묶인 함수의 조합니다. 즉, 클로저는 내부 함수에서 외부 함수의 범위에 대한 접근을 제공합니다. Javascript에서 클로저는 함수 생성 시 함수가 생성될 때마다 생성됩니다. 출처-MDN

사실 우리는 코딩을 하면서 이미 클로저를 자주 사용해왔습니다. 클로저 구조는 다음과 같습니다.

function outer() {
  let x = 10;
  function inner() {
    console.log(x); 
  }
  return inner;
}

outer(); // 10

위 코드의 결과가 왜 10이 나올까요? 코드가 다음과 같이 실행되기 때문입니다.

  • outer 함수 안에는 x라는 변수가 있고, inner라는 내부 함수가 x를 사용합니다.
  • outer 함수가 실행되면 inner 함수를 반환하는데, 이때 inner 함수는 outer 함수의 변수 x를 기억하고 있습니다.
  • 그래서 closureExample()을 호출하면 inner 함수가 실행되어 x를 출력하게 됩니다.

위 처럼 클로저란, 함수 안에 정의된 다른 함수가 외부 함수의 변수에 접근할 수 있게 해주는 구조입니다. 그렇다면 자바스크립트에서는 이런 클로저가 왜 가능한 걸까요?


2️⃣ 자바스크립트에서 클로저

자바스크립트에서 클로저가 가능한 이유는 렉시컬 환경(Lexical Environment)실행 컨텍스트(Execution Context) 덕분입니다. 자바스크립트는 렉시컬 스코프를 따르기 때문에, 함수가 어디에 선언되었는지에 따라 변수의 유효 범위가 결정됩니다. 이를 기반으로 클로저가 형성됩니다.

렉시컬 스코프란?
함수의 선언 위치에 따라 변수의 유효 범위(스코프)가 정해지는 것을 말합니다. 즉, 함수 내에서 참조할 수 있는 변수들은 그 함수가 선언된 위치를 기준으로 결정됩니다.

렉시컬 환경

렉시컬 환경이란 변수나 함수가 어디서 정의되었는지를 기억하고 관리하는 개념입니다.

렉시컬 환경을 구성하는 두가지 요소가 있습니다.

  1. 환경 레코드는 변수와 함수들이 실제로 저장되는 저장소를 말합니다. 함수안에서 선언된 변수나 함수들이 여기에 저장되고 변수의 값을 찾을 때 여기서부터 시작해서 찾게됩니다.
  2. 상위 환경에 대한 참조는 해당 변수를 다른 곳에서 찾도록 해주는 역할을 합니다. 예를 들어 함수 안에서 외부 함수의 변수의 접근하려면 상위 환경을 찾아야하는데 이 때 이 참조가 필요하게 됩니다.

실행 컨텍스트

실행 컨텍스트는 자바스크립트 코드가 실행될 때 생성되는 실행 환경을 의미 합니다. 즉, 자바스크립트 엔진이 코드를 해석하고 실행하는 동안의 환경을 말하며 함수 호출이나 코드 블록이 실행될 때 새로운 실행 컨텍스트를 생성합니다.

실행 컨텍스트의 구성 요소는 크게 렉시컬 환경, 변수 객체, this 값이 있습니다.

  1. 렉시컬 환경은 변수나 함수가 어디서 선언 되었는지를 기억하고 저장합니다.
  2. 변수 객체는 변수와 함수 선언이 포함된 객체로 함수 내에서 사용되는 변수들이 저장됩니다.
  3. this 값은 함수가 어디서 실행되었는지에 따라서 동적으로 결정됩니다.

정리하자면,

  • 렉시컬 환경을 통해 변수와 함수 선언이 어디서 정의되었는지를 추적하고 변수의 스코프를 결정합니다.
  • 실행 컨텍스트는 코드 실행 시 생성되는 실행 환경으로 렉시컬 환경을 포함하고 있어 함수가 실행될 때마다 변수에 접근할 수 있도록 도와줍니다.

따라서, 렉시컬 환경을 통해 변수와 함수의 선언 위치를 추적하고 이를 바탕으로 실행 컨텍스트 내에서 변수에 접근 할 수 있도록 도와주기 때문에 클로저가 가능하게 됩니다.


3️⃣ 클로저 활용 예시

클로저는 다음과 같은 일을 가능하게 합니다.

데이터의 은닉화

데이터의 은닉화는 외부에서 특정 데이터를 직접 수정하지 못하도록 하고, 그 데이터를 수정하는 메서드만을 제공하는 방식입니다. 이를 통해 중요한 데이터를 보호하고, 예기치 않은 변경을 방지할 수 있습니다.

function createCounter() {
  let count = 0; // 외부에서는 접근할 수 없는 변수
  return {
    increment: function() {
      count++;
      console.log(count);
    },
    decrement: function() {
      count--;
      console.log(count);
    },
    getCount: function() {
      return count;
    }
  };
}

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

이 예시에서 count 변수는 createCounter 함수 내부에 정의되어 있으며, 외부에서 직접 접근할 수 없습니다. 대신, 클로저를 통해 반환된 메서드(increment, decrement, getCount)만 사용하여 값을 변경하거나 조회할 수 있습니다. 이렇게 데이터를 은닉하고 외부에서의 직접적인 접근을 차단하는 방식으로 데이터의 은닉화가 이루어집니다.

함수형 프로그래밍

함수형 프로그래밍은 함수를 일급 객체로 취급하며, 함수들이 다른 함수를 반환하거나 인자로 받을 수 있는 특징이 있습니다. 클로저는 이러한 함수형 프로그래밍에서 유용하게 사용됩니다. 특히, 내부 함수가 외부 상태에 의존하면서 그 상태를 기억하는 데 클로저가 사용됩니다.

function multiply(factor) {
  return function(number) {
    return number * factor;
  };
}

const multiplyBy2 = multiply(2);
const multiplyBy3 = multiply(3);

console.log(multiplyBy2(5)); // 10
console.log(multiplyBy3(5)); // 15

위 코드에서 multiply 함수는 내부에서 또 다른 함수를 반환합니다. 이때 반환된 함수는 factor 변수에 접근할 수 있는데, 이는 클로저 덕분입니다. 클로저를 사용하면 외부 함수의 인자 값을 기억하는 고차 함수를 쉽게 구현할 수 있으며, 이러한 방식은 함수형 프로그래밍에서 자주 사용됩니다

콜백 함수 및 비동기 작업

클로저는 비동기 작업에서 상태를 유지하는 데 유용하게 사용됩니다. 비동기 작업이 완료된 후 콜백 함수가 실행될 때 외부 함수의 변수에 접근할 수 있습니다.

function fetchData(url) {
  let data = null;
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      data = `Fetched data from ${url}`;
      resolve(data);
    }, 1000);
  });
}

function displayData() {
  fetchData('https://api.example.com').then(data => {
    console.log(data); // "Fetched data from https://api.example.com"
  });
}

displayData();

위 코드에서 fetchData 함수는 비동기적으로 데이터를 가져오는 작업을 합니다. 데이터가 가져와지면, then 안의 콜백 함수에서 data를 사용할 수 있습니다. 이때 data는 fetchData 함수 내에서 정의된 변수입니다. 비록 비동기 작업이 완료되었지만, 클로저 덕분에 비동기 작업 후에도 data에 접근할 수 있는 것입니다. 이처럼 클로저는 비동기 작업에서 중요한 역할을 하며, 작업이 끝난 후에도 데이터를 안전하게 사용할 수 있게 합니다.


🙌🏻 마무리

사실 클로저는 새로운 개념은 아니고 이미 알고 있고 사용하는 개념이었습니다. 클로저에 대해 정확히 정의하고, 자바스크립트에서 왜 가능한지를 이해함으로써 자바스크립트의 동작 원리를 더욱 깊이 이해할 수 있었습니다. 특히 그동안 통신할 때 사용했던 비동기 처리 방식을 이해하는데 큰 도움이 됐습니다. 원리를 이해하고 사용하는 것의 중요성을 다시 한번 느끼면서 20000...

profile
개발댕발

0개의 댓글

관련 채용 정보