코드노트

변수의 생명 주기 / 전역변수, 지역변수/ var의 문제점 정리, let, const 본문

Code note/자바스크립트

변수의 생명 주기 / 전역변수, 지역변수/ var의 문제점 정리, let, const

코드노트 2022. 12. 9. 21:44

var 키워드

변수는 선언에 의해서 생성되고 할당을 통해 값을 갖게 된다.
그리고 언젠가 소멸한다.
* 변수에 생명 주기가 없다면 한번 선언된 변수는 프로그램을 종료하지 않는 한 영원히 메모리 공간을 점유하게 된다.

변수는 자신이 선언된 위치에서 생성되고 소멸한다.

전역 변수의 생명 주기는 애플리케이션의 생명 주기와 같다.
하지만 함수 내부에서 선언된 지역 변수는 함수가 호출되면 생성되고 함수가 종료하면 소멸한다.


전역 변수의 생명주기

- 전역 변수 : 변수 선언은 다른 코드가 실행되기 이전인 런타임 이전 단계에서 자바스크립트 엔진에 의해 먼저 실행 된다.
- 함수와는 달리 명시적인 호출이 없어도 실행
* 마지막 문이 실행되어 더 이상 실행할 문이 없을 때 종료
- var 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 된다.

더보기

전역객체

- 코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체

- 클라이언트 사이드 환경(브라우저)에서는 window, 서버 사이드 환경(Node.js)에서는 global 객체를 의미

- 환경에 따라 전역 객체를 가리키는 다양한 식별자가 존재했으나 ES11에서 globalThis로 통일

- 표준 빌트인 객체(Object, String, Number, Function, Array..)와 환경에 따른 호스트 객체(클라이언트 Web API 또는 Node.js의 호스트 API), 그리고 var 키워드로 선언한 전역 변수와 전역 함수를 프로퍼티로 갖는다.

* 전역객체, 전역변수는 App을 종료하지 않는한 계속 살아있다.


지역 변수의 생명주기

- 지역 변수 : 함수가 호출되기 이전까지 생성되지 않는다.
- 지역 변수의 생명 주기는 함수의 생명 주기와 일치한다.

var x = "global";

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

foo();
console.log(x); // "global"

- 첫번째 console에서 undefined가 나오는 이유는?
- foo() 함수를 호출하게 되면 var 변수는 선언이 된다. 그러나 할당이 된 상태는 아니다.
- 그 상태에서 x는 선언만 되어있고, "local"은 할당되지 않았다. 그래서 undefined가 나오는걸 볼 수 있다.
* 이렇게 호이스팅은 스코프 단위로 동작하는걸 알 수 있다.


전역 변수의 문제점

암묵적 결합
- 전역 변수를 선언하는 의도는 어디에서나 전역 변수를 사용하겠다는 것
- 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합(implicit coupling)을 허용하는 것
- 변수의 유효 범위가 크면 클수록 코드의 가독성은 나빠지고, 의도치 않게 상태가 변경될 수 있다.

▶ 긴 생명 주기
- 메모리 리소스도 오랜 기간 소비
- 전역 변수의 상태를 변경할 수 있는 시간도 길며, 모든 함수가 참조할 수 있기 때문에 상태를 변경할 기회도 많다.
* 지역변수를 사용하면 생명주기가 짧고, 변경 가능한 기회도 짧을 수 밖에 없다. Error가 발생할 확률이 적어진다.

▶ 스코프 체인 상에서 종점에 존재
- 스코프 체인 상에서 종점에 존재한다. 즉 전역 변수가 가장 마지막에 검색 된다는 것을 말한다.
- 적연 변수의 검색 속도가 지역변수보다 느리다. 속도가 그렇게 차이가 나지는 않지만 확실한건 느리고, 속도의 차이가 있다.

▶ 네임스페이스 오염
- 가장 큰 문제점 중의 하나는 js파일이 분리되어 있다 하여도 하나의 전역 스코프를 공유한다는 것
- 다른 파일 내에서 동일한 이름으로 명명된 변수나 함수가 같은 스코프 내에 존재할 경우 예상치 못한 결과를 가져올 수 있다.


전역 변수 사용 억제 방법!

- 전역 변수를 반드시 사용하여야 할 이유를 찾지 못한다면 지역 변수를 사용하여야 한다.
- 변수의 스코프는 좁을수록 좋다.

즉시 실행 함수

- 모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다.

(function () {
  var foo = 10; // 즉시 실행 함수
})();

네임 스페이스 객체 / 그렇게 유용하지는 않다.

- 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법

var MYAPP = {};
MYAPP.name = "kwon";
console.log(MYAPP.name); // kwon

모듈 패턴

- 클래스를 모방에서 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈로 만든다.
- 모듈 패턴은 클로저 기반으로 동작

자바스크립트 클로저(Closure) 정리

클로저(Closure) - 함수와 함수가 선언된 어휘적 환경(렉시컬 환경)의 조합 -> 내부함수가 외부함수 변수에 접근 가능 function init() { // name은 init에 의해 생성된 지역 변수 var name = "Mozilla"; // displayName

codeno-te.tistory.com

- 전역 변수의 억제, 캡슐화까지 구현

var Counter = (function () {
  var num = 0;
  // 외부로 공개할 데이터나 메소드를 프로퍼티로 추가한 객체를 반환
  return {
    increase() {
      return ++num;
    },
    decrease() {
      return --num;
    },
  };
})();

// 변수는 외부로 노출되지 않는다.
console.log(Counter.num);

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

ES6 모듈

- ES6 모듈을 사용하면 더는 전역 변수를 사용할 수 없다.
- ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공
- 모듈 내에서 var키워드로 선언한 변수는 전역 변수가 아니며, window객체의 프로퍼티도 아니다.

  <script type="module" src="/a.mjs"></script>
  <script type="module" src="/b.mjs"></script>

var 키워드 문제점
- var 키워드로 선언한 변수는 중복 선언이 가능
- 같은 스코프 내에서 변수를 중복 선언하면 마지막에 선언한 할당값이 적용된다.
- 만약 동일한 변수 이름이 이미 선언되어 있는 것을 모르고 중복 선언하면 변수값이 변경되는 부작용이 발생


let, const 키워드

- 중복선언을 하면 문법 에러가 발생!
- 변수 호이스팅이 발생하지 않는 것처럼 동작 // 레퍼런스 에러 발생
- 블록 레벨 스코프를 가진다.

let 키워드

- var키워드와는 다르게 선언단계에서 레퍼런스 에러가 발생한다.
- 일시적 사각지대(TDZ)로 변수 호이스팅이 발생하지 않는것처럼 보인다.
- 선언문 이후로 참조할 수 있다.

- let키워드로 선언한 전역 변수는 전역 객체로 사용할 수 없다.

const 키워드

- 상수를 선언하기 위해사용 / 그러나 반드시 상수만을 위해 사용하지는 않는다.
- 대부분의 특징은 let과 동일 하다.
- 재할당이 금지 된다.
- 변수 이름을 대문자로 선언하여 상수임을 명확히 나타낸다.
- 원시 값을 할당할 경우에는 값을 변경할 수 없지만, 객체를 할당한 경우 값을 변경할 수 있다.


* 변수를 선언할 때 기본적으로는 const로 사용
* 재할당이 필요한 경우에는 let을 사용 / 변수의 스코프는 최대한 좁게!
- const로 선언 후 재할당이 필요하다면 let키워드로 변경해도 늦지 않다.