14장 전역 변수의 문제점

hyewon ji·2023년 2월 16일

전역변수의 무분별한 사용은 위험하다. 전역변수를 반드시 사용해야 할 이유가 없다면 지역변수를 사용해야 한다.

1. 변수의 생명 주기

변수는 선언에 의해 생성되고 할당을 통해 값을 갖는다.
변수는 생명 주기가 있다. 자신이 선언된 위치에서 생성되고 소멸한다.

전역변수는 런타임 이전 단계에서 자바스크립트 엔진에 의해 먼저 생성되고, 프로그램이 종료되면 소멸한다.
지역변수함수가 호출된 직후 코드가 한줄씩 순차적으로 실행되기 이전에 자바스크립트 엔진에 의해 생성되고, 함수가 종료되면 소멸한다.

변수는 값을 저장하기 위해 확보한 메모리 공간을 식별하기 위해 붙인 이름이다. 즉, 변수의 생명 주기메모리 공간이 확보된 시점부터 해제되어 가용 메모리 풀에 반환되는 시점까지이다.

함수 내부에 선언된 지역 변수는 함수가 생성한 스코프에 등록되고 스코프가 소멸(메모리 해제)될때까지 유효하다. 할당된 메모리 공간은 더 이상 그 누구도 참조하지 않을 때 가비지 콜렉터에 의해 해제되어 가용 메모리 풀에 반환된다.

var x = 'global';

function foo() {
  console.log(x);
  var x= 'local';
}

// 호출 직후 지역 변수 x가 선언, 초기화됨
// 함수가 종료되면 해제됨
foo();

console.log(x); // global

2. 전역 변수의 생명 주기

전역 변수는 특별한 진입점이 없고 코드가 로드되자마자 곧바로 해석되어 선언되고, 문이 모두 실행되면 종료된다.
전역변수는 전역 객체의 프로퍼티가 된다. 즉, 전역 변수의 생명주기가 전역 객체의 생명 주기와 일치한다.

전역변수의 문제점은 다음과 같다.

1. 암묵적 결합
모든 코드가 전역변수를 참조하고 변경할 수 있다.
변수의 유효범위가 크면 클수록 코드의 가독성이 나빠지고 의도치 않은 상태 변경이 일어날 수 있다.

2. 긴 생명 주기
메모리 리소스가 많이 소요되고, 생명 주기 동안 변수명의 중복 및 재할당이 일어날 수 있다.

3. 스코프 체인 상에서 종점에 존재
전역 변수는 스코프 체인 상에서 종점에 존재하기 때문에 검색속도가 가장 느리다.

4. 네임스페이스 오염
다른 파일 내에 동일한 변수명이 존재할 경우 예상치 못한 결과를 발생 시킬수 있다.

3. 전역 변수의 사용 억제하는 방법

1. 즉시 실행 함수
모든 코드를 즉시실행 함수로 감싸면 모든 변수는 즉시 실행함수의 지역 변수가 된다.
라이브러리 등에서 많이 사용되는 방법이다.

(function () {
  const foo = 10;
}());

console.log(foo) // ReferenceError: foo is not defined

2.네임스페이스 객체
네임스페이스 역할을 담당할 객체를 생성하고 전역 변수로 사용하고 싶은 변수를 프로퍼티로 추가하는 방법이다.
이 방법은 결국 네임스페이스 객체가 전역 변수에 할당되므로 좋은 대안은 아니다.

const MYAPP = {};

MYAPP.name = 'Lee';

console.log(MYAPP.name); // Lee

3. 모듈 패턴
클래스를 모방해 관련있는 변수와 함수를 모아 즉시 실행함수로 하나의 모듈을 만든다.이 방법은 전역 변수의 억제캡슐화가 가능하다.

캡슐화를 하면 정보 은닉을 할 수 있다. 자바스크립트는 객체지향 프로그래밍 언어에서 제공하는 접근 제한자(public, private, protected)를 제공하지 않기 때문에 모듈 패턴을 사용해 정보 은닉을 구현할 수 있다.

var Counter = (function () {
  let num = 0;
  
  return {
    increase() {
      return ++num;
    },
    decrease() {
      return --num;
    }
  }
}())

console.log(Counter.num); // undefined

console.log(Conuter.increase()); // 1
console.log(Conuter.increase()); // 2
console.log(Conuter.decrease()); // 1
console.log(Conuter.decrease()); // 0

반환되는 객체나 함수는 퍼블릭, 반환되지 않는 객체나 함수는 프라이빗 멤버이다.

4. ES6 모듈
ES6 모듈을 파일 자체의 독자적인 모듈 스코프를 제공한다. 따라서 모듈 내에 선언한 변수는 전역변수가 아니며 window 객체의 프로퍼티도 아니다.

모던 브라우저(Chrome 61, FF 60, SF 10.1, Edge 16이상)에서는 ES6 모듈을 사용할 수 있다. script 테그에 type="module" 어트리뷰트를 추가해 사용할 수 있다. 모듈 파일의 확장자는 mjs를 권장한다.

<script type="module" src="lib.mjs"></script>

ES6 모듈은 IE를 포함한 구형 브라우저에서는 동작하지 않고, 트랜스파일링이나 번들링이 필요하기 때문에
아직까지는 Webpack 등의 모듈 번들러를 사용하는 것이 일반적이다.

0개의 댓글