Global

자바스크립트에서 글로벌 스코프는 코드 전체에서 접근할 수 있는 가장 넓은 범위를 의미하며, 여기서 선언된 변수나 함수는 프로그램 전반에서 사용이 가능하다.

자바스크립트의 전역 스코프는 코드의 어느 위치에서나 접근할 수 있는 최상위 스코프이다.
전역 변수와 함수는 편리하게 사용할 수 있지만, 이름 충돌, 의도치 않은 수정, 메모리 관리 등의 문제를 일으킬 수 있다.

현대 자바스크립트 개발에서는 모듈 시스템, 클로저, 네임스페이스 패턴 등을 활용하여 전역 스코프의 사용을 최소화하고, 코드를 논리적인 단위로 구성하는 것이 좋은 관행으로 여겨진다.

전역 스코프란 무엇인가?

전역 스코프는 자바스크립트 코드의 최상위 레벨에서 선언된 변수와 함수가 속하는 영역이다.
이 영역에서 선언된 요소들은 코드의 모든 부분에서 접근할 수 있다.

브라우저 환경에서 전역 스코프는 window 객체와 연결되며, Node.js 환경에서는 global 객체와 연결된다.
웹 브라우저에서 전역 변수를 선언하면 자동으로 window 객체의 속성이 된다.

1
2
3
4
5
6
7
8
9
// 전역 변수 선언
var globalVar = "전역 변수입니다";
console.log(window.globalVar); // "전역 변수입니다" (브라우저 환경에서)

// 전역 함수 선언
function globalFunction() {
  console.log("전역 함수입니다");
}
window.globalFunction(); // "전역 함수입니다" (브라우저 환경에서)

글로벌 변수 선언 및 사용 방법

  • var 키워드 사용

    1
    2
    3
    
    var globalVar = "I'm global";
    console.log(globalVar);         // 콘솔에 "I'm global" 출력
    console.log(window.globalVar);  // 브라우저 환경에서는 window 객체를 통해도 접근 가능
    

    var로 선언하면 전역 변수는 window 객체의 속성이 되는 특성이 있다.

  • let 및 const 키워드 사용

    1
    2
    3
    4
    
    let globalLet = "I'm global but not on window";
    const PI = 3.14159;
    console.log(globalLet);         // 코드 전반에서 접근 가능
    console.log(window.globalLet);  // 브라우저 환경에서는 undefined 출력
    

    letconst를 사용하면 변수는 전역적으로 접근 가능하지만, 글로벌 객체에 등록되지 않아 네임스페이스 오염을 줄일 수 있다.

전역 스코프의 특징

  1. 접근성
    전역 스코프에 선언된 변수와 함수는 어디서든 접근 가능하다.
    이는 코드의 어느 부분에서도 해당 변수와 함수를 사용할 수 있다는 의미이다.

    1
    2
    3
    4
    5
    6
    7
    
    var globalVar = "나는 전역 변수입니다";
    
    function someFunction() {
      console.log(globalVar); // 함수 내에서도 전역 변수에 접근 가능
    }
    
    someFunction(); // "나는 전역 변수입니다"
    
  2. 생명 주기
    전역 변수는 프로그램이 실행되는 동안 메모리에 존재한다.
    이는 웹 페이지가 로드된 후부터 페이지를 떠나거나 새로고침할 때까지 계속된다.

  3. 선언 방식에 따른 차이
    전역 스코프에서 변수를 선언하는 방식에 따라 특성이 달라진다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    // var 키워드로 선언 - window 객체의 속성이 됨
    var varVariable = "var로 선언된 변수";
    console.log(window.varVariable); // "var로 선언된 변수"
    
    // let 키워드로 선언 - window 객체의 속성이 되지 않음
    let letVariable = "let으로 선언된 변수";
    console.log(window.letVariable); // undefined
    
    // const 키워드로 선언 - window 객체의 속성이 되지 않음
    const constVariable = "const로 선언된 변수";
    console.log(window.constVariable); // undefined
    
    // 키워드 없이 선언 - 항상 전역 객체의 속성이 됨 (엄격 모드가 아닌 경우)
    noKeywordVariable = "키워드 없이 선언된 변수";
    console.log(window.noKeywordVariable); // "키워드 없이 선언된 변수"
    

전역 스코프의 문제점

  1. 이름 충돌
    전역 스코프의 가장 큰 문제점은 이름 충돌(name collision)이다.
    여러 스크립트나 라이브러리를 사용할 때, 동일한 이름의 전역 변수를 선언하면 충돌이 발생할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    
    // script1.js
    var userName = "홍길동";
    
    // script2.js (나중에 로드됨)
    var userName = "김철수"; // 기존 userName을 덮어씀
    
    console.log(userName); // "김철수"
    
  2. 의도치 않은 수정
    전역 변수는 코드 어디에서나 수정할 수 있기 때문에, 의도치 않은 변경이 발생할 가능성이 높다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    var counter = 0;
    
    function incrementCounter() {
      counter++; // 전역 변수 수정
    }
    
    function resetCounter() {
      counter = 0; // 전역 변수 수정
    }
    
    // 다른 함수나 스크립트에서도 counter를 수정할 수 있음
    
  3. 메모리 사용
    전역 변수는 프로그램이 실행되는 동안 계속 메모리에 존재하기 때문에, 불필요하게 많은 전역 변수를 사용하면 메모리 사용량이 증가할 수 있다.

전역 스코프의 대안과 모범 사례

  1. 즉시 실행 함수 표현식(IIFE)
    IIFE는 함수를 선언하고 즉시 실행하는 패턴으로, 변수를 전역 스코프에서 분리할 수 있다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    (function() {
      // 이 안에 선언된 변수는 외부에서 접근할 수 없음
      var privateVar = "비공개 변수";
    
      // 필요한 경우 전역 객체에 특정 함수나 변수를 노출
      window.publicFunction = function() {
        console.log(privateVar);
      };
    })();
    
    console.log(typeof privateVar); // "undefined"
    publicFunction(); // "비공개 변수"
    
  2. 모듈 패턴
    모듈 패턴은 IIFE를 확장하여 비공개 상태와 공개 인터페이스를 가진 모듈을 생성한다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    var myModule = (function() {
      // 비공개 변수 및 함수
      var privateVar = "비공개 데이터";
    
      function privateFunction() {
        console.log("비공개 함수입니다");
      }
    
      // 공개 API 반환
      return {
        publicVar: "공개 데이터",
        publicFunction: function() {
          console.log(privateVar);
          privateFunction();
        }
      };
    })();
    
    myModule.publicFunction(); // "비공개 데이터" 및 "비공개 함수입니다" 출력
    console.log(myModule.privateVar); // undefined (접근 불가)
    
  3. ES6 모듈
    ES6부터는 공식적인 모듈 시스템이 도입되어, 파일 단위로 스코프를 분리할 수 있게 되었다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    // module.js
    export const moduleName = "ES6 모듈";
    
    export function moduleFunction() {
      console.log("모듈 함수입니다");
    }
    
    // main.js
    import { moduleName, moduleFunction } from './module.js';
    
    console.log(moduleName); // "ES6 모듈"
    moduleFunction(); // "모듈 함수입니다"
    
  4. 네임스페이스 패턴
    네임스페이스 패턴은 전역 객체 오염을 줄이기 위해 단일 전역 객체를 생성하고, 그 안에 기능을 정의하는 방식이다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 단일 전역 객체 생성
var MyApp = MyApp || {};

// 네임스페이스 추가
MyApp.utils = {
  formatDate: function(date) {
    // 날짜 형식 변환 로직
    return date.toISOString();
  },
  
  validateEmail: function(email) {
    // 이메일 유효성 검사 로직
    return /\S+@\S+\.\S+/.test(email);
  }
};

// 사용
console.log(MyApp.utils.formatDate(new Date())); // ISO 형식의 날짜 문자열
console.log(MyApp.utils.validateEmail("test@example.com")); // true

전역 실행 컨텍스트와 전역 환경

자바스크립트 엔진이 코드를 실행할 때, 가장 먼저 전역 실행 컨텍스트를 생성한다.
전역 실행 컨텍스트는 코드 실행을 위한 기본 환경을 제공하며, 전역 변수와 함수를 관리한다.

전역 환경 레코드는 전역 실행 컨텍스트의 일부로, 전역 스코프에서 선언된 모든 변수와 함수를 기록한다.
이는 두 가지 구성 요소로 나뉜다:

  1. 객체 환경 레코드: 전역 객체(window, global)와 관련된 바인딩을 저장한다.
  2. 선언적 환경 레코드: let, const로 선언된 변수와 같은 선언을 저장한다.

참고 및 출처