Post

[모던 자바스크립트 Deep Dive]14장 전역 변수의 문제점

14.1 변수의 생명 주기

  • 생명 주기: 메모리 공간이 확보(allocate)된 시점 ~ 메모리 공간이 해제(release)되어 가용 메모리 풀(memory pool)에 반환되는 시점
  • 전역 변수의 생명 주기: 애플리케이션의 생명 주기

14.1.1 지역 변수의 생명 주기

1
2
3
4
5
6
7
8
9
var x = "global";

function foo() {
  console.log(x); // undefined
  var x = "local";
}

foo();
console.log(x); // global
  • 지역 변수의 생명 주기: 함수의 생명 주기
  • 호이스팅은 스코프를 단위로 동작
    • 함수 내의 변수는 전역 변수의 호이스팅과 달리, 함수가 실행될 때 호이스팅 된다.
    • 즉, 호이스팅 = 변수 선언이 스코프의 선두로 올라온 것처럼 동작
  • 정확히는, 변수는 자신이 등록된 스코프가 소멸(메모리 해제)할 때까지 유효
    • 할당된 메모리 공간이 더 이상 참조되지 않을 때 가비지 콜렉터가 이를 해제해서 가용 메모리 풀에 반환

14.1.2 전역 변수의 생명 주기

  • 전역 코드
    • 특별한 진입점 없이 코드가 로드되면 곧바로 해석 및 실행
    • 더 이상 실행할 문이 없을 때 종료
  • 전역 객체
    • 코드 실행 전 자바스크립트 엔진이 생성하는 특수한 객체
    • 클라이언트 사이드 환경(브라우저)에서는 window, 서버 사이트 환경(Node.js)에서는 global 객체
      • 참고로 window는 웹페이지를 닫기 전까지 유효
    • 전역 객체를 가리키는 식별자는 ES11부터 globalThis로 통일
    • 프로퍼티
      • 표준 빌트인 객체
        • Object, String, Number, Function, Array
      • 환경에 따른 호스트 객체
        • 클라이언트 Web API 또는 Node.js의 호스트 API
      • **var 키워드로 선언한 전역 변수**와 전역 함수
  • var 키워드로 선언한 전역 변수 = 전역 객체의 생명 주기

14.2 전역 변수의 문제점

  • 암묵적 결합(implicit coupling)
    • 모든 코드가 전역 변수를 참조 및 변경 가능
    • 변수의 유효 범위가 커져 가독성이 나빠지고 상태가 의도치 않게 변경될 수 있다.
  • 긴 생명 주기
    • 메모리 리소스를 오랜 기간 소비
    • 상태가 의도치 않게 변경될 수 있는 시간이 길어짐
      • 심지어 var 키워드는 변수의 중복 선언도 허용
        1
        2
        3
        4
        5
        6
        7
        
        var x = 1;
        
        // ...
        
        // 변수의 중복 선언. 기존 변수에 값을 재할당한다.
        var x = 100;
        console.log(x); // 100
        
  • 스코프 체인 상에서 종점에 존재
    • 변수 검색 시 전역 변수가 가장 마지막에 검색된다.
  • 네임 스페이스 오염
    • 파일이 분리되어 있어도 하나의 전역 스코프를 공유하므로 다른 파일에 중복된 이름이 존재할 수 있다.

14.3 전역 변수의 사용을 억제하는 방법

14.3.1 즉시 실행 함수

1
2
3
4
5
6
(function () {
  var foo = 10; // 즉시 실행 함수의 지역 변수
  // ...
})();

console.log(foo); // ReferenceError: foo is not defined
  • 즉시 실행 함수: 정의와 동시에 단 한 번만 호출
  • 코드를 즉시 실행 함수로 감싸, 변수를 즉시 실행 함수의 지역 변수로 만드는 방법
  • 라이브러리 등에 자주 사용되는 방법

14.3.2 네임스페이스 객체

1
2
3
4
5
var MYAPP = {}; // 전역 네임스페이스 객체

MYAPP.name = "Lee";

console.log(MYAPP.name); // Lee
  • 전역에 네임스페이스 역할을 할 객체를 생성하고, 전역 변수처럼 사용하고 싶은 변수를 프로퍼티에 추가
  • 네임스페이스 객체를 중첩으로 넣어 계층을 만들 수 있다.
  • 식별자 충돌은 방지하지만, 네임스페이스 객체가 전역 변수에 할당되어 좋은 방법은 아니다.

14.3.3 모듈 패턴

  • 모듈 패턴: 관련이 있는 변수와 함수를 즉시 실행 함수 안에 모아 넣어 하나의 모듈 생성
    • 클래스를 모방
    • 전역 변수 억제캡슐화 구현 가능
  • 캡슐화: 프로퍼티와 메서드를 하나로 묶는 것으로, 정보은닉도 가능
    • 프로퍼티: 객체의 상태
    • 메서드: 프로퍼티를 참조하고 조작할 수 있는 동작(behavior)
    • 정보 은닉: 객체의 특정 프로퍼티나 메서드를 감추는것
  • 접근 제한자(access modifier): 공개 범위를 한정하는 제한자
    • 자바스크립트를 빼고 대부분의 객체 지향 프로그래밍 언어가 사용
    • public, private, protected
    • 모듈 패턴을 사용해 접근 제한자를 사용한 것 같은 효과를 줄 수 있다.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      
      var Counter = (function () {
        // private 변수
        var num = 0;
      
        // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환한다.
        return {
          increase() {
            return ++num;
          },
          decrease() {
            return --num;
          },
        };
      })();
      
      // private 변수는 외부로 노출되지 않는다.
      console.log(Counter.num); // undefined
      
      console.log(Counter.increase()); // 1
      console.log(Counter.increase()); // 2
      console.log(Counter.decrease()); // 1
      console.log(Counter.decrease()); // 0
      

14.3.4 ES6 모듈

  • ES6 모듈은 파일 자체의 독자적인 모듈 스코프 제공
    • ES6 모듈 내에서 var 키워드로 선언한 변수는 전역 변수가 아니다.
  • script 태그에 type = "module" 속성을 추가하면 로드된 자바스크립트 파일은 모듈로서 동작
    • 모듈 파일 확장자는 mjs 권장
      1
      2
      
      <script type="module" src="lib.mjs"></script>
      <script type="module" src="app.mjs"></script>
      
This post is licensed under CC BY 4.0 by the author.