Skip to main content

14장 전역변수의 문제점

14.1 변수의 생명주기

  • 선언(변수생성)→할당(값을 가짐)→소멸

생명주기가 없으면 한번 선언된 변수는 프로그램을 종료하지 않는 한 영원히 메모리공간 점유

변수는 선언된 위치에서 생성-소멸

전역변수의 생명주기: 애플리케이션의 생명주기와 동일

지역변수의 생명주기: 함수 호출:생성→ 함수종료:소멸 . 함수 호출(함수 내부 변수 선언문 실행) 이전까지는 생성되지 않음

변수선언: 위치 상관 없이 가장 먼저 실행됨. 코드가 한 줄씩 순차적으로 실행되는 런타임 실행시가 아니라 런타임 이전단계에서 자바스크립트엔진에 의해 먼저 실행됨. -전역변수 한정

함수내부 선언변수: 함수호출된 직후 런타임 이전 자바스크립트엔진에 의해 먼저 실행됨.

function foo() {
var x = "local"; // 변수x 생성
console.lgo(x); // 변수x에 값 할당
return x; // 변수x 소멸
}

//함수 몸체 내부에서 선언된 지역변수의 생명주기: 함수의 생명주기와 대부분 일치 또는 함수보다 오래 생존.

변수: 하나의 값을 저장하기 우해 확보한 메모리 공간 그 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름 변수의 생명주기: 메모리 공간이 확보(allocate)된 시점 ~ 메모리 공간이 해제(release)되어 가용 메모리 풀(memory pool)에 반환되는 시점

⇒ 등록된 스코프가 소멸(메모리 해제)될 때까지 유효

더 이상 그 누구도 참조하지 않을 때 가비지콜럭터에 의해 해제되어 가용메모리풀에 반환됨. == 누군가 메모리공간을 참조할 경우 해제되지 않고 확보된 상태로 남음

== 누군가 스코프를 참조하고 있으면 소멸ㄴ ㄴ 생존

→ 함수 종료시 함수가 생성한 스코프도 소멸. 단 누군가 이 스코프를 참조하고 있을 경우 해제되지 않고 생존

var x = "global";
function foo() {
console.log(x); //1: undefined
var x = "local";
console.log(x); //2: 'local'
}

//foo함수 내부에 선언된 '지역변수x'는 1의 시점에 이미 선언되어있고 undefined로 초기화되어있음
//따라서 '전역변수x'를 참조하는게 아니라 '지역변수x'를 참조해 값을 출력.
// 즉, 지역변수는 함수 전체에서 유효함.
// 단, 변수할당문이 실행되기 전까지는 undefined

foo();
console.log(x); //3: global
  • 호이스팅(hoisting)
  • 스코프 단위로 동작
  • 변수 선언이 스코프의 선두로 끌어올려진것처럼 동작하는 자바스크립트 고유의 특징
  • 전역변수: 전역변수의 선언이 전역 스코프의 선두로 끌어올려진것처럼 동작→전역전체에서 유효
  • 지역변수: →함수 전체에서 유효

14.2 전역 변수의 문제점

  • 전역코드:
  • 함수와 달리 명시적 호출 없이 실행 === 전역코들르 실행하는 특별한 진입점(entry point)없음
  • 코드가 로드되자 마자 곧바로 해석되고 실행됨.
  • 함수: 함수의 마지막문 또는 반환문 실행시 종료
  • 전역코드: 마지막문이 실행되어 더이상 실행할 문이 없을 때 종료. 반황문을 사용할수 없기때문
  • C, JAVA로 작성된 코드를 실행⇒ 가장먼저 main함수 호출(main함수=== 진입점).
  • 전역객체(global object):
  • 코드가 실행되기 이전단계에 자바스크립트엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체
  • 클라이언트 사이드환경(브라우저)에서는 window,
  • 서버 사이드환경(node.js)에서는 global객체를 의미
  • 과거 환경에 따라 전역 객체를 가리키는 다양한 식별자(window, self, this, frames, global)존재했음 ⇒ 현재 ES11에서 globalThis로 통일됨
  • 표준 빌트인 객체(Object, String, Number, Function, Array, ...)와 환경에 따른 호스트 객체(클라이언트 Web API 또는 Node.js의 또는 호스트 API), 그리고 var키워드로 선언한 전역변수와 전역함수를 프로퍼티로 갖는다.
  • var키워드로 선언한 전역변수: 전역 객체의 프로퍼티가 된다===전역변수의 생명주기가 전역객체의 생명주기와 일치
  • 전역. 즉 코드 어디서든 참조/할당 가능한 변수
  • 브라우저 환경에서 전역객체: window -웹페이지를 닫기 전까지 유효 ⇒ 브라우저 환경에서 var키워드로 선언한 전역변수 === 전역객체 window의 프로퍼티

[전역변수의 문제점]

  • 암묵적 결합(implicit coupling) 코드 어디서든 참조/할당 가능한 변수⇒ 모든 코드가 전역변수를 참조/변경할 수 있는 암묵적 결합허용됨 변수의 유효범위 클수록 코드 가독성 떨어짐. 의도치않은 상태변화 위험도 높아짐.
  • 긴 생명주기 ==-메모리 리소스 오랜기간 소비. 상태변경 가능기간,기회 높아짐. var키워드의 경우 중복선언 허용됨⇒변수이름 중복되어 의도치않은 재할당 위험
  • 스코프 체인상에서 종점에 존재===변수 검색시 전역변수가 가장마지막에 검색됨
  • 네임스페이스의 오염
  • 자바스크립트 문제점: 파일이 분리되어있어도 하나의 전역스코프를 공유함. ⇒ 다른파일 내에서도 동일한 이름으로 명명된 전역변수나 전역함수가 같은 스코프 내에서 존재할 경우 예상치 못한 결과...

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

전역변수를 반드시 사용해야할 이유를 찾지 못한다면 지역변수를 사용해야한다.

변수의 스코프는 좁을 수록 좋다

  • 즉시실행함수
  • 함수 정의와 동시에 호출됨.
  • 단 한번만 호출됨.
  • 모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시실행 함수의 지역변수가 된다.
(function () {
var foo = 10; //즉시실행 함수의 지역변수
})();

console.log(foo); //undefined
  • 네임스페이스 객체
  • 전역에 네임스페이스(namespace)역할을 담당할 객체를 생성⇒전역변수처럼 사용하고 싶은 변수를 프로퍼티로 추가
var My = {}; //전역 네임스페이스 객체
My.name = "Seo";
console.log(My.name); //"Seo"

// 네임스페이스 분리=> 식별자 충돌 방지효과.
// 결국엔 My도 전역변수에 할당되므로 그다지 유용...
  • 모듈패턴: 클래스 모방. 관련 변수와 함수를 모아 즉시실행 함수로 감싸 하나의 모듈로 만듬
  • 자바스크립트 클로저 기반으로 동작 (즉, 클로저를 통해 전역변수 억제 가능)
  • 전역변수 억제 및 캡슐화까지 구현가능

캡슐화(encapsulation) :

— 객체의 상태(state)를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작(behavior)인 메서드를 하나로 묶는것 — 객체의 특정 프로퍼티나 메서드 감출목적(정보은닉; information hiding) — 객체지향 프로그래밍언어: 클래스를 구성하는 멤버에 public(외부접근가능), private(내부만), protected등의 접근제한자(access modifier)를 사용→ 공개범위 한정⇒ 원치않는 외부접근으로부터 내부 보호

— 자바스크립트는 접근제한자 제공안함 ⇒ 모듈패턴으로 정보은닉 가능(외부에서 지역변수호출 불가)

public member: 프로퍼티 외부에 노출 private member: 외부에서 접근 불가

  • ES6 모듈
  • 파일 자체의 독자적인 모듈 스코프를 제공⇒ 모듈 내 var키워드로 선언한변수는 더이상 전역변수 아님, window객체의 프로퍼티도 아님.

-IE를 포함한 구형 브라우제에서 동작 안함

-트랜스파일링이나 번들링필요. 따라서 Webpack등의 모듈 번들러를 사용.