관리 메뉴

흰둥씨의 개발장

[자바스크립트] 딥다이브 ) 전역변수의 문제점 본문

BoOk/JS deep dive

[자바스크립트] 딥다이브 ) 전역변수의 문제점

돈워리비해삐 2023. 6. 14. 01:47

1) 변수의 생명주기

  - 1) 지역 변수의 생명 주기 

ㄴ 변수는 생물과 유사하게 생성되고 소멸되는 생명 주기(life cycle)가 있음
(변수의 생명주기는 메모리 공간이 확보allocate된 시점부터 메모리 공간이 해제release되어 가용 메모리 풀에 반환되는 시점까지임)

ㄴ 전역변수의 생명주기는 애플리케이션의 생명주기와 같음

ㄴ지역변수의 생명주기는 함수의 생명주기와 일치함(함수내 선언된 변수는 함수가 호출되어 실행되는 동안에만 유효함 = 함수내 선언된 변수는 자신이 등록된 스코프가 소멸될때 까지 유효함, 할당된 메모리공간은 누구도 더이상 참조 하지 않을 때 가비지 콜렉터에 의해 화르륵)

ㄴ변수는 자바스크립트 엔진에 의해 런타임 이전에 먼저 실행됨 
(함수내 선언된 변수는 함수 호출시, 다른 문들이 순차 실행되기 전 변수의 선언문이 자바스크립트 엔진에 의해 undefined로 초기화 되고,
함수내 코드가 순차적으로 실행되면서 해당 변수에 값이 할당됨)

let x = '전역변수'; 

function sibal(){
console.log(x)
let x = '로컬변수';
} 

sibal(); //레퍼런스 에러 (x에 undefined로 초기화 된상태로 호이스팅 되고나서 console.log(undefined)로 에러=> x에 값 할당됨)
console.log(x);  //전역변수

 

  - 2 ) 전역 변수의 생명주기

ㄴ전역 코드는 함수호출처럼 특별함 진입점 없이 코드가 로드되자마자 해석되고 실행됨 
(마지막문 실행되어 더이상 실행할 문이 없을 때 종료함)

ㄴ var키워드로 선언한 전역변수는 전역객체의 프로퍼티임 (전역변수의 생명주기 = 전역객체의 생명주기)

전역객체 ? 클라이언트 사이드 환경(브라우저)에서는 window, 서버사이드 환경(node.js)에서는 global객체를 의미 
(자바스크립트 엔진에 의해 런타임전 생성되는 특수한 객체 / 환경에 따라 전역 객체를 가리키는 다양한 식별자가 있었지만 ES11부터는 globalThis로 통일됨)

ㄴ전역객체의 프로퍼티 : 표준 빌트인 객체(object, string, number, function, array...), 환경에 따른 호스트객체(클라이언트 웹API, node.js의 호스트 API), var키워드로 선언한 전역변수, 전역함수

ㄴex)브라우저 환경에서 전역객체는 window이므로 브라우저 환경에서 var로 선언된 변수는 전역객체 window의 프로퍼티이며, window는 웹페이지를 닫기전까지 유효하기 때문에,  var로 선언된 변수도 웹페이지를 닫을 때 까지 유효함

 

2 ) 전역변수의 문제점 

  - 1) 암묵적 결합 (implicit coupling)
ㄴ모든 코드가 어디서든 참조하고 변경할 수 있음 (의도치 않게 상태가 변경될수 있고, 가독성도 안좋아짐)

  - 2) 긴 생명주기
ㄴ전역변수는 지역변수보다 훨씬 생명주기가 길다 (= 메모리 리소스도 오랜기간 소비한다 = 상태변경할수 있는 시간도 기회도 많음)

  - 3) 스코프 체인 상에서 종점에 존재 
ㄴ변수검색할 때 전역 변수가 가장 마지막에 검색되어서 전역변수의 검색속도가 가장 느린편 

  - 4) 네임스페이스 오염
ㄴ자바스크립트는 파일이 분리되어 있어도 하나의 전역스코프를 공유함( => 예기치못한 결과 가져올수 있음)

 

3) 전역변수 사용을 억제하는 방법
      => 지역변수를 사용하자 (스코프를 좁힐수록 좋음)

- 1) 즉시실행함수 

(function(){
	let sival = 18; //즉시 실행함수의 지역변수
}());
console.log(sival);  //referenceError

 

  - 2) 네임스페이스 객체 
ㄴ전역에 네임스페이스 역할 할 객체를 생성해서, 전역변수 처럼 사용하고 싶은 변수를 프로퍼티로 추가하기

let MYNAMEIS = {}; // 전역 네임스페이스 객체

	MYNAMEIS.name = 'Conan';

console.log(MYNAMEIS.name); // Conan

	MYNAMEIS.person = { //계층적으로 구성하기
		name = 'Kim',
		address: '서울'
   	}
console.log(MYNAMEIS.person.name); // Kim

 

  - 3) 모듈 패턴 
ㄴ(클로저편에서 자세히 다룰예정, 정보은닉을 구현하기 위해 사용함)
캡슐화 : 객체 상태(state)를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할수 있는 동작인 메서드를 하나로 묶는 것
캡슐화는 정보은닉목적에서 아주 good(특정 프로퍼티나 메서드를 감추는 것)
ㄴ객체지향 언어는 대체로 접근제한자(public, private, protected...)를 사용해 공개범위를 한정할 수 있음
ㄴ접근제한자는 자바에는 있고, 자바스크립트에는 없음

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

console.log(Counter.num); //undefiend  => private 변수는 외부로 노출되지 않음

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

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

 

   - 4) ES6모듈 
ㄴES6모듈을 사용하면 파일자체의 독자적인 모듈스코프를 제공하기 때문에, 전역변수를 사용할 수 없음
ㄴscript태그에 type="module" 속성을 추가하면 로드된 js파일은 모듈로써 동작하고, 파일 확장자는 mjs권장함
ㄴ모듈내 var로 선언된 변수는 전역변수가 아니고, window객체 프로퍼티도 아님 
ㄴ하지만, IE같은 구형브라우저에서 동작하지 않음(모던브라우저는 사용가능)
ㄴ또, 브라우저의 ES6모듈기능을 사용하더라도 트렌스파일링or번들링 필요해서 웹팩의 모듈번들러 쓰는것이 일반적

<script type="module" src="index.mjs" />