무분별한 전역변수 사용 지양해야 함
(1) 변수의 생명 주기
- 선언에 의해 생성 → 할당을 통해 값 가짐 → 소멸
- 자신이 선언된 위치에서 생성되고 소멸함
전역 변수
의 생명 주기= 애플리케이션의 생명 주기
- 함수 내부에서 선언된
지역변수
= 함수 호출시 생성 → 함수 종료시 소멸 - = 함수의 생명주기와 같음
❗지역 변수가 함수보다 오래 생존하는 경우
변수
: 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메로리 공간을 식별하기 위해 붙인 이름- 생명주기: 메모리 공간이 확보된 시점 ~ 메모리 공간이 해제되어 가용 메모리 풀에 반환되는 시점
- 함수 내부에서 선언된 변수 = 함수가 생성한 스코프에 등록
- 함수가 생성한 스코프 = 물리적인 실체 존재 (렉시컬 환경)
- 변수: 자신이 등록된 스코프가 소멸(메모리 해제)될 때까지 유효
- 할당된 메모리 공간 더이상 참조 X → 가비지 콜렉터에 의해 해제되어 가용 메모리 풀에 반환됨
- 누군가가 메모리 공간 참조 → 해제되지 않고 확보된 상태로 남아있게 됨
- 스코프도 변수와 마찬가지 ⇒ 누군가가 스코프 참조시 소멸하지 않고 생존
- 일반적으로 함수가 종료하면 함수가 생성한 스코프도 소멸
- 누군가가 스코프 참조시 해제되지 않고 생존
var x = 'global';
function foo() {
console.log(x);
var x = 'local';
}
foo(); // undefined
console.log(x); // global
- foo 내부에서 선언된 x는 foo 호출 직후에 선언되며 undefined로 초기화됨
- 변수 할당문이 실행되기 이전까지 undefined 값 가짐
호이스팅
: 변수 선언이 스코프의 선두로 끌어 올려진 것처럼 동작하는 자바스크립 고유의 특징- 스코프 단위로 동작함
- 전역 변수의 호이스팅: 전역 변수의 선언이 전역 스코프의 선두로 끌어 올려진 것처럼 동작
- 지역 변수의 호이스팅: 지역 변수의 선언이 지역 스코프의 선두로 끌어 올려진 것처럼 동작
- 지역 변수는 함수 전체에서 유효함
전역 변수의 생명 주기
- 전역 코드
- 명시적인 호출 없이 실행됨
- 함수 호출과 같이 전역 코드를 실행하는 특별한 진입점이 없음
- 로드되자마자 곧바로 해석 후 실행
- 마지막 문이 실행되어 더 이상 실행할 문이 없을 때 종료
- 함수
- 함수 몸체의 마지막 문 또는 반환문이 실행되면 종료
전역 객체
코드가 실행되기 이전에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체
- 환경에 따른 객체
- 클라이언트 사이드 환경(브라우저) =
window
- 서버 사이드 환경(Node.js) =
global
- 환경에 따라 전역 개체 가리키는 다양한 식별자 존재
window.self
,this, frames
,global
- ES11에서
globalThis
로 통일
- 클라이언트 사이드 환경(브라우저) =
- 전역 객체가 갖는 프로퍼티
- 표준 빌트인 객체
- Object, String, Number, Function, Array
- 환경에 따른 호스트 객체
- 클라이언트 Web API, Node.js의 호스트 API
- var 키워드로 선언한 전역 변수와 전역 함수
- 표준 빌트인 객체
- var 키워드로 선언된 변수 =
전역 객체
의 프로퍼티가 됨⇒ 전역 변수의 생명 주기 = 전역 객체의 생명 주기- 브라우저 환경에서 var 키워드로 선언한 전역 변수 = 전역 객체 window의 프로퍼티
- 전역 객체 window : 웹페이지 닫기 전까지 유효
- var 키워드로 선언된 변수도 마찬가지
- 전역 객체 window : 웹페이지 닫기 전까지 유효
- 브라우저 환경에서 var 키워드로 선언한 전역 변수 = 전역 객체 window의 프로퍼티
(2) 전역 변수의 문제점
- 전역변수 선언 의도 = 암묵적 결합 허용
암묵적 결합
- 모든 코드가 전역 변수를 참조하고 변경할 수 있는 것
- 코드 어디서든 참조하고 할당할 수 있는 변수 선언하는 것
- 변수의 유효 범위 ↑ ⇒ 코드 가독성 ↓ & 의도치 않은 상태 변경 위험성 ↑
- 전역 변수의 긴 생명 주기 → 오랜 메모리 리소스 소비 기간 → 전역 변수 상태 변경 가능성 ↑
- 전역변수는 스코프 체인 상에서 종점에 존재⇒ 변수 검색 시 가장 마지막에 검색 되므로 검색 속도 가장 느림
- 네임 스페이스 오염
- JS의 가장 큰 문제점
- 하나의 파일이 분리되었다고 해도 하나의 전역 스코프를 공유한다는 점
- 다른 파일 내에서 동일한 이름으로 명명된 전역 변수·함수 같은 스코프에 존재할 가능성 有 ⇒ 예상치 못한 결과 초래
- 하나의 파일이 분리되었다고 해도 하나의 전역 스코프를 공유한다는 점
- JS의 가장 큰 문제점
(3) 전역 변수의 사용을 억제하는 방법
- 전역 변수 사용할 이유 없다면 지역 변수 사용해야 함
- 변수의 스코프는 좁을수록 좋음
방법1 ) 즉시 실행 함수
- 즉시 실행 함수: 함수 정의와 동시에 단 한번만 호출
- 모든 코드 즉시 실행 함수로 감쌀 시 모든 변수는 즉시 실행 함수의 지역 변수가 됨
방법2 ) 네임 스페이스 객체
- 전역에 네임 스페이스를 담당할 객체 생성 후 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법
- 네임 스페이스 객체에 또 다른 네임 스페이스 객체를 프로퍼티로 추가하여 네임스페이스 계층적 구성 가능
- 네임 스페이스 분리하여 식별자 충돌을 방지 가능
- 네임 스페이스 객체 자체가 전역 변수이므로 크게 유용 x
var MYAPP = {};
MYAPP.name = 'Lee';
MYAPP.person = {
name: 'Lee',
address: 'Seoul',
}
방법3 ) 모듈 패턴
- 클래스를 모방해서 관련 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈 생성
- 클로저를 기반으로 동작
- 자바스크립트의 가장 강력한 기능
- 캡슐화 구현 가능
프로퍼티
와메서드
를 하나로 묶는 것- 프로퍼티: 객체의 상태를 나타냄
- 메서드: 프로퍼티를 참조하고 조작할 수 있는 동작
- 객체의 특정 프로퍼티나 메서드를 감출 목적으로도 사용 ⇒
정보 은닉
- 전역 네임스페이스의 오염 방지와 정보 은닉 구현 목적으로 사용
var Counter = ( function() { var num = 0; // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체 반환 return { increase(){ return num++; }, decrease(){ return num--; } } } ()); // private 변수는 외부로 노출되지 않음 console.log(Counter.num); // undefined console.log(Counter.increase()); // 1 console.log(Counter.decrease()); // 0
- 위 예제의 즉시 실행 함수: 객체 반환
- 외부에 노출하고 싶은 변수나 함수를 담아 반환
퍼블릭 멤버
: 반환되는 객체의 프로퍼티 (외부에 노출됨)
프라이빗 멤버
: 외부로 노출하고 싶지 않은 변수나 함수- 반환하는 객체에 추가하지 않으면 됨
- 외부에 노출하고 싶은 변수나 함수를 담아 반환
- 위 예제의 즉시 실행 함수: 객체 반환
방법4 ) ES6 모듈
- ES6 모듈 사용시 전역 변수 사용 불가능
- 파일 자체의 독자적인 모듈 스코프 제공
- 모듈 내에서 var 키워드로 선언한 변수≠ 전역변수
- ≠ window 객체의 프로퍼티
- 모던 브라우저에서 사용 가능
- script 태그에 type=”module” 어트리뷰트 추가시 로드된 자바스크립트 파일 = 모듈로서 동작
- 모듈 확장자 =
mjs
- 모듈 확장자 =
- 브라우저의 ES6 모듈 기능 사용시 트랜스파일링, 번들링 필요⇒
일반적인 사용
브라우저 지원 ES6 모듈 기능 < 모듈 번들러 (ex. Webpack)