[14장] 전역 변수의 문제점
⚠️ 전역 변수의 무분별한 사용은 위험!
14.1 변수의 생명 주기
14.1.1 지역 변수의 생명 주기
- 변수는 선언에 의해 생성되고 할당을 통해 값을 갖고, 언젠가는 소멸 ⇒ 생명 주기 존재
- 전역 변수의 생명 주기 = 애플리케이션의 생명 주기
function foo() {
var x = "local";
console.log(x);
return x;
}
foo();
console.log(x);
- 변수 선언은 선언문이 어디에 있든 상관없이 가장 먼저 실행됨. 즉, 변수 선언은 런타임에 실행되는 것이 아닌 런타임 이전 단계에서 JS 엔진에 의해 먼저 실행됨 ⇒ 전역 변수에 한정된 설명
- 함수 내부에서 선언한 변수는 함수가 호출된 직후에 함수 몸체의 코드가 한 줄씩 순차적으로 실행되기 이전에 JS 엔진에 의해 먼저 실행됨

- 지역 변수의 생명주기 = 함수의 생명 주기(지역 변수가 함수보다 오래 생존하는 경우도 존재)
- 변수는 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
- 변수의 생명주기는 메모리 공간이 확보(allocate)된 시점부터 메모리 공간이 해제(release)되어 가용 메모리 풀에 반환되는 시전까지
- 변수는 자신이 등록된 스코프가 소멸될 때까지 유효
- 할당된 메모리 공간은 더 이상 그 누구도 참조하지 않을 때 가비지 콜렉터에 의해 해제되어 가용 메모리 풀에 반환됨 → 누군가 메모리 공간을 참조하고 있으면 해제되지 않고 확보된 상태로 남아있음
- 스코프 역시, 누군가 스코프를 참조하고 있으면 스코프는 소멸하지 않고 생존, 함수가 종료하면 함수가 생성한 소코프도 소멸
var x = "global";
function foo() {
console.log(x);
var x = "local";
}
foo();
console.log(x);
14.1.2 전역 변수의 생명 주기
[전역 변수 특징]
- 함수와 달리 전역 코드는 명시적인 호출 없이 실행됨. 즉, 특별한 진입점이 없고 코드가 로드되자마자 곧바로 해석되고 실행됨
- 함수는 함수 몸체의 마지막 문 또는 반환문이 실행되면 종료함. 하지만, 전역 코드에는 반환문을 사용할 수 없으므로 마지막 문이 실행되어 더 이상 실행할 문이 없을 때 종료

- var 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 됨 ⇒ 전역 변수의 생명 주기 = 전역 객체의 생명 주기
전역 객체: 코드가 실행되기 이전 단계에 JS 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체
→ window(클라이언트 사이드 환경=브라우저), global(서버 사이드 환경) 등(ES11 부터는 globalThis로 통일됨)
→ 표준 빌트인 객체(Object, String, Number, Function, Array,..), 호스트 객체, var 키워드로 선언한 전역 변수와 전연 함수를 프로퍼티로 가짐
14.2 전역 변수의 문제점
- 암묵적 결합
- 전역 변수를 선언한 의도는 코드 어디서든 참조하고 할당할 수 있는 변수를 사용하겠다는 것 ⇒ 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합 허용
- 변수의 유효 범위가 크면 클수록 코드의 가독성은 나빠지고 의도치 않게 상태가 변경될 수 있는 위험성도 높아짐
- 긴 생명 주기
- 전역 변수는 생명 주기가 긺 → 메모리 리소스도 오랜 기간 소비함, 전역 변수의 상태를 변경할 수 있는 시간도 길고 기회도 많음
- var 키워드는 변수의 중복 선언을 허용하므로 생명 주기가 긴 전역 변수는 변수 이름이 중복될 가능성 존재
- 스코프 체인 상에서 종점에 존재
- 전역 변수는 스코프 체인 상에서 종점에 존재 → 변수를 검색할 때 전역 변수가 가장 마지막에 검색됨 = 전역 변수의 검색 속도가 가장 느림
- 네임스페이스 오염
- 다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우 예상치 못한 결과 유발
14.3 전역 변수의 사용 억제하는 방법
❗️ 전역 변수를 반드시 사용해야할 이유를 차지 못한다면 지역 변수를 사용하기! 변수의 스코프는 좁을수록 좋음
14.3.1 즉시 실행 함수
(function () {
var foo = 10;
})();
console.log(foo);
- 함수 정의와 동시에 호출되는 즉시 실행 함수는 단 한 번만 호출됨
- 모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 됨
14.3.2 네임스페이스 객체
- 전역에 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법
var MYAPP = {};
MYAPP.name = "Lee";
console.log(MYAPP.name);
- 네임스페이스 객체에 또 다른 네임스페이스 객체를 프로퍼티로 추가해서 네임스페이스를 계층적으로 구성 가능
var MYAPP = {};
MYAPP.person = {
name: "Lee",
address: "Seoul",
};
console.log(MYAPP.person.name);
14.3.3 모듈 패턴
- 클래스를 모방해서 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈로 만듦
- 모듈 패턴은 클로저를 기반으로 동작
- 전역 변수의 억제 뿐만 아니라 캡슐화까지 구현 가능
- JS에서는 public, private, protected 등의 접근 제한자 제공 X
-
public
멤버: 반환되는 객체의 프로퍼티
-
private
멤버: 외부로 노출하고 싶지 않은 변수나 함수는 반환하는 객체에 추가하지 X
var Counter = (function () {
var num = 0;
return {
increase() {
return ++num;
},
decrease() {
return --num;
},
};
})();
console.log(Counter.num);
console.log(Counter.increase());
console.log(Counter.increase());
console.log(Counter.decrease());
console.log(Counter.decrease());
14.3.4 ES6 모듈