[JS] 14. 전역변수

heyhey·2023년 7월 13일
0
post-thumbnail

14. 전역변수

전역 변수는 위험하다 라는 말이 많습니다.
왜 전역변수가 위험하고, 사용을 억제할 수 있는 방법에 대해 알아보겠습니다.

14.1 변수의 생명 주기

지역 변수의 생명 주기

지역 변수가 위험한 이유는 생명 주기와 연관이 있습니다.

변수는 선언에 의해 생성되고 할당을 통해 값을 가지고 소멸하는 과정을 생명 주기라고 합니다.

생명주기가 없다면, 계속해서 메모리 공간을 점유하게 될 것입니다.

보통의 변수는 자신이 선언된 위치에서 생성되고 소멸합니다.
함수 내부에서 선언된 지역 변수는 함수가 종료되면 소멸하는 반면,
전역 변수는 어플리케이션이 종료될때까지 지속됩니다.

function foo() {
  var x = "local";
  console.log(x);
  return x;
}
foo();
console.log(x); // x is not defined

지역 변수 x는 foo 함수의 호출과 동시에 생성됩니다.
그리고 함수가 끝날때 소멸되어, 생명 주기가 종료됩니다.

지역변수의 생명 주기는 함수의 생명 주기와 일치합니다.

복습 ) 변수 선언은 코드가 런타임에 실행되는 것이 아니라, 이전 단계에서 실행됩니다. => 호이스팅

변수의 생명 주기라는 것은 메모리 공간이 확보된 시점부터, 메모리 공간이 해제되어 가용 메모리 풀에 반환되는 시점까지입니다.

함수 내부에서 선언된 지역 변수는 함수가 생성한 스코프에 등록됩니다.
함수가 생성한 스코프는 렉시컬 환경이라 불리는 물리적인 실체가 있습니다.

할당된 메모리 공간은 참조하지 않으면, 가비지 콜렉터에 의해 해제되어 메모리 풀에 반환됩니다.

만약에 메모리 공간을 누군가가 참조하고 있으면, 해제되지 않고 확보된 상태로 남아있게 됩니다.
스코프도 같은 원리로, 누군가가 참조하고 있으면 스코프는 소멸되지 않고 생존합니다. (클로저)

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

전역변수가 있더라도 스코프 안에서 먼저 지역변수를 먼저 참조합니다.
호이스팅은 스코프를 단위로 동작하기 때문에, 값을 조회하면 undefined가 나오게 됩니다.

전역 변수의 생명 주기

전역 코드는 명시적인 호출이 없이 실행되기 때문에 전역 변수는 진입점 없이 코드가 실행됩니다.

전역 코드에는 반환문이 없기 때문에 더이상 실행할 문이 없을 때 종료하게 됩니다.

전역 변수를 선언하면 전역 객체의 프로퍼티가 됩니다.

전역 객체?
전역 객체는 client 환경에서는 window, 서버 사이드에서는 global 객체를 의미합니다.
환경에 따라 전역 객체를 가리키는 식별자가 존재했으나 (this,global,window) globalThis로 통일되었습니다.
전역 객체는 표준 빌트인객체 (Object,String,Number,Function..) 와 환경에 따른 호스트객체, 그리고 전역 변수와 전역 함수를 프로퍼티로 갖습니다.

브라우저 환경에서 전역변수로 선언한 값은 window 의 프로퍼티 입니다.
여기서의 전역변수는 웹 페이지를 닫을 때까지 유효하게 됩니다.

브라우저 환경

var a = 5;
window.a; // 5

const b = 3;
window.b; // undefined

14.2 전역 변수의 문제점

암묵적 결합

전역변수를 선언한 의도는 코드 어디서든 참조 가능한 변수를 사용하겠다는 것입니다.
모든 코드가 전역 변수를 참조 가능하고 변경이 가능하게 됩니다.
이걸 암묵적 결합 허용이라고 합니다.

=> 의도치 않은 상태 변경 위험 가능성이 생기게 됩니다.

긴 생명 주기

생명 주기가 길어서 메모리 리소스도 오랜 기간 소비하게 됩니다.
중복 선언을 허용하기 때문에 변수 이름이 중복될 가능성도 있습니다.

=> 의도치 않은 재할당이 생겨버릴 수 있습니다.

지역변수를 사용하면 짧은 생명 주기로,

  • 상태변경에 의한 오류의 확률이 줄어들게 됩니다.
  • 메모리 리소스도 짧은 기간만 소비합니다.

스코프 체인 상에서 종점에 존재

전역 변수는 검색하면 가장 마지막에 검색이 되기 때문에, 검색 속도가 느립니다.

네임스페이스 오염

파일이 분리되어 있어도 동일한 이름의 변수는 예상치 못한 결과를 가져올 수 있습니다.

14.3 전역 변수 사용 억제 방법

전역 변수를 지양하고, 지역 변수를 최대한 사용합니다.
변수의 스코프는 좁을수록 좋습니다.

즉시 실행 함수

모든 코드를 즉시 실행 함수로 감싸버리면 모든 변수는 즉시 실행 함수의 지역 변수가 됩니다.

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

이런식으로 사용하면, 전역 변수를 생성하지 않기 때문에 라이브러리에서 자주 사용하는 방식입니다.

네임 스페이스 객체

전역에 네임스페이스 객체를 만들어 주고, 변수를 프로퍼티로 추가해서 사용하는 방법도 있습니다.

var GLOBAL_VAR = {};
GLOBAL_VAR.name = "HONG";

식별자 충돌은 방지하나, 크게 유용하진 않아 보입니다.

모듈 패턴

모듈 패턴은 클래스를 모방해 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만듭니다.

모듈 패턴은 클로저를 기반으로 작동합니다.
전역 변수의 억제와 캡슐화까지 구현 가능합니다.

캡슐화란 객체의 상태(state) 를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것입니다.

캡슐화는 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 합니다.
이를 은닉이라고 합니다.

C나 자바는 public,private,protected 등의 접근 제한자를 공개 범위를 한정지을 수 있습니다.
JS에서는 이런 접근 제한자가 없기 때문에 모듈을 사용합니다.

var Counter = (function () {
  var num = 0;
  return {
    increse() {
      return ++num;
    },
    decrease() {
      return --num;
    },
  };
})();
Counter.increase(); // 1
Counter.increase(); // 2
Counter.decrease(); // 1

클래스와 비슷하게 생겼습니다.
즉시 실행 함수는 객체를 반환합니다. 이 객체에는 외부에 노출하고 싶은 변수나 함수를 담아 반환합니다.
외부에 노출되면 public , 반환을 하지 않으면, private 입니다.

ES6 모듈

ES6 를 사용하면 전역 변수를 사용할 수 없습니다.
ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공합니다.

var 로 선언한 변수는 전역 변수가 아니게 됩니다.

<sciprt></sciprt>에 type="module" 을 추가하면, JS 파일은 모듈로서 동작합니다.

하지만, 트랜스파일링이나 번들링이 필요하기 때문에, 브라우저가 지원하는 ES6 모듈보다는
Webpack 등의 모듈 번들러를 사용하는 것이 일반적입니다.

profile
주경야독

0개의 댓글