본문 바로가기

카테고리 없음

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

1. 변수의 생명주기


변수는 생성되고 소멸되는 생명주기(Life Cycle)가 있다.

  • 전역변수의 생명주기 : 애플리케이션의 생명주기
  • 지역변수의 생명주기 : 함수의 생명주기
function foo() { var x = 'local'; console.log(x); // local return x; } foo(); console.log(x); // ReferenceError: x is not defined

위 예제에서 지역변수 x는 foo 함수가 호출되기 이전까지는 생성되지 않는다.
전역 변수는 변수 호이스팅으로 인해서 전역코드가 실행되기 전에 실행되어 생성된다. 그러나 함수 내부에서 선언된 지역변수는 함수가 호출된 직후에 함수 몸체 내의 코드가 실행되기 전에 실행된다.

알아야 할 점.

호이스팅은 스코프 단위로 동작한다.
-> 호이스팅은 변수 선언이 스코프의 선두로 끌어 올려진 것 처럼 동작하는 자바스크립트 고유의 특징!

전역 변수의 생명주기

전역 코드는 명시적인 호출 없이 코드가 로드되자마자 곧바로 해석되고 실행된다.
var 키워드로 선언한 전역 변수는 전역객체 window의 프로퍼티가 된다. 여기서, window는 웹페이지가 닫을 때 까지 유효하므로 결국 var 키워드로 선언한 전역 변수의 생명주기는 전역 객체의 생명주기와 일치한다.

2. 전역 변수의 문제점

  1. 암묵적 결합
    • 모든 코드가 전역 변수를 참조하고 변경할 수 있음을 허용하는 것
  2. 긴 생명 주기
    • 메모리 리소스가 오랜 기간 소비
    • 전역 변수의 상태를 변경할 수 있는 시간 ↑
    • 변수 이름이 중복된 가능성 ↑ (var 키워드는 변수의 중복 선언을 허용하기 때문!)
  3. 스코프 체인 상에서 종점에 존재
    • 전역변수가 스코프 체인 상에서 가장 끝에 존재하므로 전역변수의 검색 속도가 가장 느리다.
  4. 네임스페이스 오염
    • 다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우 예상치 못한 결과를 가져올 수 있다.

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


1. 즉시 실행 함수

(function () { var foo = 10; // 즉시 실행 함수의 지역 변수 // ... }()); console.log(foo); // ReferenceError: foo is not defined

모든 코드를 즉시 실행함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다.
-> 라이브러리 등에 자주 사용

2. 네임스페이스 객체

var MYAPP = {}; // 전역 네임스페이스 객체 MYAPP.person = { name: 'Lee', address: 'Seoul' }; console.log(MYAPP.person.name); // Lee

전역에 네임스페이스를 담당할 객체를 생성하고 변수를 프로펴티로 추가하는 방식
-> 식별자 충돌을 방지할 수는 있으나 네임스페이스 객체 자체가 전역 변수이므로 그다지 좋지는 못하다.

3. 모듈 패턴

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

클로저를 기반으로 한 즉시실행 함수로 감싼 모듈로 구현하여 사용하는 방식
-> 전역변수의 억제와 캡슐화까지 구현 가능

4. ES6 모듈

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

script 태그에 type="module" 어트리뷰트를 추가하여 ES6 모듈로 동작시키는 방법
-> ES6 모듈을 사용하게되면 전역변수를 사용할 수 없게 된다.
-> 파일 자체의 독자적인 모듈 스코프를 제공한다.

정리

전역 변수의 무분별한 사용은 위험하므로 반드시 사용해야 할 이유가 없다면 지역변수를 사용하는 것이 좋다.
-> 변수의 스코프는 좁을수록 좋다.