본문 바로가기
Javascript/javascript

자바스크립트에서의 클로저 활용과 함께하는 스코프 이해하기

by 노마드 산코디 2023. 8. 29.
728x90

자바스크립트에서의 클로저 활용과 함께하는 스코프 이해하기

 

 

안녕하세요!

 

이번 포스팅에서는 자바스크립트의 핵심적인 주제 중 하나인 클로저와 스코프에 대해 깊이 있는 내용을 정리해보려고 합니다. 클로저와 스코프는 자바스크립트 프로그래밍에서 중요한 개념으로, 이해하고 활용하는 것이 프로그래밍 실력을 높이는데 큰 도움이 될 것입니다. 함께 이 두 가지 개념을 자세히 살펴보도록 하겠습니다.

 

 


스코프의 이해

자바스크립트의 스코프는 변수의 유효 범위를 나타내는 개념입니다. 간단하게 말해서 변수가 어디에서 선언되었는지에 따라 해당 변수에 접근할 수 있는 범위가 결정됩니다. 이는 변수의 가시성과 접근성을 관리하는 역할을 합니다.

 

스코프는 크게 전역 스코프와 지역 스코프로 나뉩니다. 전역 스코프는 코드 어디에서든 접근할 수 있는 범위를 의미하며, 함수 내부에서 선언된 변수는 그 함수 내에서만 접근할 수 있는 지역 스코프를 가집니다.

변수가 스코프 내에서 정의되었다면 해당 스코프와 그 스코프를 포함하는 다른 스코프에서 해당 변수를 사용할 수 있습니다. 하지만 스코프 외부에서는 해당 변수에 접근할 수 없습니다. 이를 통해 변수 이름의 충돌을 방지하고 코드의 모듈성과 유지 보수성을 높일 수 있습니다.

스코프는 코드 블록(주로 함수) 내에 선언된 변수가 해당 블록 내에서만 유효하게 하는 등, 변수의 생명주기와 관련된 중요한 역할을 하며, 자바스크립트 프로그래밍에서 필수적인 개념 중 하나입니다.

 

 


변수의 선언

자바스크립트에서 변수를 선언하는 방법에는 두 가지가 있습니다: var와 let 또는 const입니다. 각각의 변수 선언 방식은 스코프 내에서 변수의 유효 범위와 생명 주기를 다르게 처리합니다.

var
   - var는 함수 스코프(function scope)를 가집니다. 함수 내에서 선언된 변수는 해당 함수 내에서만 유효합니다.
   - 함수 내부에서 선언한 변수는 함수 내 어디에서든지 접근할 수 있습니다.
   - 함수 외부에서 선언한 변수는 전역 스코프에 속하며, 어디에서든 접근 가능합니다.
   - var 변수는 호이스팅(hoisting)되어, 선언부가 코드 상단으로 끌어올려지기 때문에 선언 이전에도 변수를 사용할 수 있습니다.

 

let
   - let은 블록 스코프(block scope)를 가집니다. 중괄호({})로 둘러싸인 코드 블록 내에서만 유효합니다.
   - 블록 내부에서 선언한 변수는 해당 블록 내 어디에서든지 접근할 수 있습니다.
   - let 변수는 호이스팅 되지만, 선언 이전에 변수를 사용하려 하면 에러가 발생합니다.

 

const
   - constlet과 마찬가지로 블록 스코프를 가집니다.
   - const 변수는 한 번 값을 할당하면 다른 값으로 변경할 수 없습니다.
   - 블록 내부에서 선언한 const 변수 역시 해당 블록 내 어디에서든지 접근 가능합니다.

 

 

스코프와 변수 선언 방식을 올바르게 활용하면 변수의 범위와 생명 주기를 관리하여 코드의 가독성과 유지 보수성을 높일 수 있습니다.

 


클로저의 활용

클로저(Closure)는 자바스크립트에서 매우 중요하면서도 강력한 개념 중 하나입니다. 클로저는 함수와 그 함수가 선언된 렉시컬 스코프(lexical scope)의 조합으로 이루어집니다. 간단히 말하면, 함수 내부에서 정의된 함수가 외부 함수의 변수에 접근할 수 있는 것을 의미합니다.


1. 외부 함수와 내부 함수

클로저는 함수 내부에서 정의된 내부 함수가 외부 함수의 변수를 참조하는 경우에 발생합니다.

2. 렉시컬 스코프

클로저 내부 함수는 자신의 스코프뿐만 아니라, 자신을 포함하는 외부 함수의 스코프도 기억합니다. 이를 렉시컬 스코프 체인(lexical scope chain)이라고 합니다.

3. 외부 함수의 변수 유지

외부 함수가 실행을 마치고 종료되더라도, 내부 함수가 외부 함수의 변수에 접근할 수 있습니다. 이는 외부 함수의 변수가 클로저 내부 함수에 의해 "캡처"되어 유지되기 때문입니다.

4. 데이터 은닉과 캡슐화

클로저를 사용하면 외부에서 직접 접근하지 못하도록 데이터를 은닉하고, 필요한 부분만을 노출하여 캡슐화할 수 있습니다.

 


클로저는 주로 콜백 함수, 비동기 처리, 모듈 패턴 등에서 사용되며, 코드의 유연성과 재사용성을 높이는 데 큰 도움을 줍니다. 클로저의 개념을 이해하고 적절하게 활용하면 더욱 효율적인 자바스크립트 코드를 작성할 수 있습니다.

 

 


메모리 관리

자바스크립트 클로저는 강력한 기능이지만 메모리 관리 측면에서 주의가 필요합니다. 클로저가 제대로 관리되지 않으면 메모리 누수(memory leaks)가 발생할 수 있습니다. 이로 인해 브라우저 성능 저하나 리소스 낭비가 발생할 수 있습니다.

클로저 메모리 관리에 대한 몇 가지 주의사항을 살펴보겠습니다.

1. 불필요한 클로저 생성 피하기

불필요한 클로저를 생성하지 않도록 주의해야 합니다. 클로저는 외부 함수의 변수를 참조하므로, 필요하지 않은 경우에도 클로저가 생성될 수 있습니다.

2. 불필요한 변수 참조 해제

클로저 내부에서 사용하는 외부 변수는 클로저가 존재하는 한 계속 유지됩니다. 따라서 클로저를 사용한 후에는 해당 변수에 대한 참조를 해제해야 합니다.

3. 이벤트 리스너 해제

이벤트 리스너에 클로저를 사용하면 해당 이벤트가 종료되어도 클로저가 계속 유지될 수 있습니다. 이벤트 리스너를 제거하지 않으면 메모리 누수가 발생할 수 있습니다.

4. 적절한 타이밍에서 클로저 해제

클로저가 더 이상 필요하지 않을 때, 해당 클로저를 제거하여 메모리를 해제해야 합니다. 이는 사용하는 라이브러리나 프레임워크에 따라 다르므로 주의가 필요합니다.

5. 모듈 패턴 활용

클로저를 모듈 패턴으로 활용하면 클로저가 필요한 변수만을 노출하여 캡슐화할 수 있습니다. 이로써 필요한 변수만 유지되며, 메모리 관리가 용이해집니다.

 


클로저 메모리 관리는 개발자의 주의와 경험에 따라 다르므로, 클로저를 사용할 때 항상 메모리 관리에 주의하며 코드를 작성하는 것이 중요합니다.

 

 


스코프와 클로저의 예제 소스 코드

 

1. 스코프 예제

function printMessage() {
  const message = "Hello, Scope!";
  console.log(message);
}

printMessage(); // 출력: Hello, Scope!
console.log(message); // 오류: message는 스코프 내에서만 접근 가능

위의 소스 코드는 printMessage라는 함수를 정의하고 호출하는 예제입니다. 함수 내에서 선언된 message 변수는 함수 스코프 내에서만 접근 가능하며, 외부에서 접근하면 오류가 발생합니다. 따라서 console.log(message)의 부분에서 오류가 발생하는 것을 확인할 수 있습니다.

 


 

2. 클로저 예제 (프라이빗 변수 생성)

function counter() {
  let count = 0; // 프라이빗 변수

  return function() {
    count++;
    console.log(count);
  };
}

const increment = counter();
increment(); // 출력: 1
increment(); // 출력: 2

위의 소스 코드는 클로저를 이용하여 카운터 함수를 생성하고 사용하는 예제입니다. counter 함수는 내부에서 count라는 변수를 선언하고, 이 변수를 활용한 함수를 반환합니다. 이렇게 반환된 함수는 클로저로서 count 변수에 접근할 수 있습니다. 따라서 increment 함수를 호출하면 count가 증가하며 출력되는 것을 확인할 수 있습니다.

 


3. 클로저 예제 (비동기 처리)

function delayPrint(message, delay) {
  setTimeout(function() {
    console.log(message);
  }, delay);
}

delayPrint("Delayed Message", 2000); // 2초 후 출력: Delayed Message

위의 소스 코드는 클로저를 이용하여 비동기적인 동작을 수행하는 예제입니다. delayPrint 함수는 메시지와 지연 시간을 인자로 받아, setTimeout 함수 내부에서 메시지를 출력하는 함수를 호출하도록 설정합니다. 이때 내부의 익명 함수는 외부의 message 변수를 참조하게 되는데, 이는 클로저로 인해 함수가 생성될 당시의 렉시컬 스코프에 접근할 수 있음을 의미합니다. 따라서 delayPrint 함수가 호출된 후 2초 뒤에 "Delayed Message"가 출력되는 것을 확인할 수 있습니다.

 


 

4. 클로저 예제 (캡슐화)

function createPerson(name) {
  let privateName = name;

  return {
    getName: function() {
      return privateName;
    },
    setName: function(newName) {
      privateName = newName;
    }
  };
}

const person = createPerson("Alice");
console.log(person.getName()); // 출력: Alice
person.setName("Bob");
console.log(person.getName()); // 출력: Bob

위의 소스 코드는 클로저를 이용하여 객체 내에서 private한 데이터를 관리하는 예제입니다. createPerson 함수는 이름을 받아서 private한 privateName 변수를 생성한 후, 객체를 반환합니다. 반환된 객체는 getName 메서드와 setName 메서드를 갖고 있는데, 이 메서드들은 클로저로서 외부 스코프의 privateName 변수에 접근할 수 있습니다.

1. createPerson 함수를 통해 person 객체를 생성하고 이름 "Alice"로 초기화합니다.

 

2. getName 메서드를 호출하여 privateName을 반환하면 "Alice"가 출력됩니다. 

 

3. setName 메서드를 호출하여 privateName을 "Bob"으로 변경합니다.

 

4. 다시 getName 메서드를 호출하면 privateName이 변경된 값인 "Bob"가 출력됩니다.

 


 

5. 스코프 체이닝과 클로저 예제

function outer() {
  const outerVar = "Outer Scope";

  function inner() {
    const innerVar = "Inner Scope";
    console.log(outerVar); // outer() 스코프에 접근 가능
    console.log(innerVar);
  }

  return inner;
}

const innerFunc = outer();
innerFunc(); // 출력: Outer Scope, Inner Scope

 

위의 소스 코드는 스코프와 클로저의 관계를 보여주는 예제입니다. outer 함수 안에 inner 함수가 중첩되어 있습니다. outer 함수는 outerVar를 선언하고 inner 함수를 반환합니다. 이때, inner 함수는 클로저로서 outer 함수의 스코프 내부에 있는 변수들에 접근할 수 있습니다.


1. outer 함수가 호출되면 outerVar 변수가 생성되고 inner 함수가 반환됩니다.

 

2. 반환된 innerFunc를 실행하면 inner 함수의 스코프 내부에 있는 innerVar와 외부 스코프인 outer 함수의 outerVar에 접근할 수 있습니다.

 

3. 결과적으로 "Outer Scope"와 "Inner Scope"가 차례대로 출력됩니다.

 

 


최종 정리

 

오늘은 자바스크립트의 스코프와 클로저에 대해 깊이 있게 알아보았습니다. 스코프는 변수가 어디에서 선언되고 접근 가능한지를 결정하는 중요한 개념으로, 이를 통해 변수의 유효 범위를 관리할 수 있습니다. 또한 클로저는 함수와 그 함수가 선언된 스코프 간의 관계를 보여주며, 함수가 외부 변수를 기억하고 참조할 수 있는 매커니즘을 제공합니다. 

 

 

그럼 다음 포스팅에도 자바스크립트의 기본적인 내용들을 주제로 정리해 보도록 하겠습니다.

 

감사합니다.

 

728x90
반응형