오늘은 전역 변수가 어떤 상황에 위험한지에 대한 부분을 다뤄볼 것인데 가장 먼저는 변수에는 "생명주기"가 있음을 짚고 넘어갈 예정이다.
변수에게는 생성되고 소멸되는 생명 주기
라는 것이 있다. 이 생명 주기가 없다면 한번 선언된 변수는 프로그램을 종료하지 않는 한 영원히 메모리 공간을 점유하게 된다.
지난 시간 복습....✍️
식별자를 추적하기 위한 수단으로 "식별자의 사용범위"를 나타내는 "스코프"는 전역 스코프와 지역스코프로 나뉘고 또 지역 스코프는 "함수 몸체 내부"와 같다고 배웠었다.
이런 스코프처럼 변수 또한 전역변수와 지역 변수로 나뉘어진다.
전역 변수의 생명주기는 어플리케이션의 생명 주기와 같고 지역 변수의 생명주기는 함수가 호출되고 종료하는 함수의 생명주기와 같다. 즉 지역 변수의 생명 주기는 함수의 생명 주기와 일치하다.
변수는 식별자이면서 메모리 공간
이다.
즉 변수의 생명 주기는 근본적으로 메모리 공간에 할당되고 해제되는 시간이다.
가비지 콜렉터는 주기적으로 메모리를 검사하며 참조값이 없는 메모리 공간은 매모리를 해제시켜 버리는데 이는 누군가가 자신의 메모리 공간을 참조하고 있다면 가비지콜렉터가 해제하지 않고 남겨둔다는 소리이다.
이러한 원리가 스코프에게도 해당한다. 스코프의 생명주기가 끝나도 누군가 스코프를 참조하고 있다면 스코프는 소멸하지 않고 생존하게 된다. 함수안에서 선언된 변수가 함수의 기능이 다 끝났음에도 불구하고 누군가 함수 밖에서 자신을 참조하고 있다면 좀비처럼 살아있을 수 있다는 이야기이다.
이것이 바로 자바스크립트의 핵심 개념 중 하나인 클로저이다.
생명 주기에 대한 이야기는 여기까지 하고
본격적으로 전역 변수의 무분별한 사용이 왜 위험한지에 대해서 다뤄보겟다.
전역변수의 생명주기는 어플리케이션 자체의 생명주기와 같다고 했다. 코드의 줄이 길어질수록 변수의 생명주기 또한 길어진다. 이는 메모리 리소스를 그만큼 오랜 기간동안 소비한다는 이야기이다.
또한 시간이 길어질수록 변수의 상태를 변경할만한 여지도 많아지기에 뒤에서 다룰암묵적 결합
이 일어날 가능성이 더 높아진다.
암묵적 결합이란 전역 변수를 참조하고 변경할 수 있는 상황을 뜻한다. 전역 변수의 유효 범위가 커질수록 변수를 어떻게 할당했었는지 기억해내기 힘들고 다시 찾아내자니 가독성이 떨어진다. 또 전역에서 참조가 가능하기에 상태가 쉽게 변경될 수 있어 위험하다.
이전 단원에서 자바스크립트 엔진은 식별자의 값을 추적할 때 실제 물리적 실체가 있는 스코프체인(렉시컬 환경)을 참조한다고 했다.
극단적인 예시로 전역 스코프에서 선언한 전역 변수를 중첩,중첩,중첩,중첩 함수 내부에서 참조한다고 가정했을 때 자바스크립트 엔진은 끝까지 상위 스코프로 올라가서 해당 변수의 값을 참조해야 한다.
이처럼 변수 중 검색 속도가 가장 느린 녀석은 전역 변수이다. 속도의 차이는 크지 않지만 차이는 분명 있다고 한다.
자바스크립트는 모듈의 기능을 지원한다.
문제는 모듈로 분리가 되어 있다고 할지라도 전역 스코프는 모든 파일에서 공유가 된다. 따라서 다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 전역 함 수가 같은 스코프 내에 존재한다면 이 또한 암묵적 결합을 야기하는 셈이다.
이렇게 위험한 전역 변수... 정말 쓰고싶지 않아진다... 꼭 필요한 상황에서만 쓰자.
함수 정의와 동시에 호출되는 즉시 실행 함수는 단 한번만 호출된다.
모든 코드를 즉시 실행 함수로 감싸면 모든 변수 또한 즉시실행함수의 지역 변수가 된다.
네임 스페이스 객체란 전역변수로 사용하고 싶은 변수들을 하나의 객체처럼 프로퍼티로 추가하는 방법인데 네임 스페이스 객체 자체가 전역 변수에 해당이 된다고 하여 유용하지 않다고 한다. 뭔가 말장난같다.
자바스크립트에서의 모듈 패턴은 클래스를 모방한 기능으로, 변수와 함수를 모아 즉시실행함수로 감싸줌으로써 하나의 모듈을 만드는 기법을 말한다.
이를 통해 자바스크립트는 캡슐화
기능을 지원하게 되어 모듈 외부에서의 접근 권한을 제어하여 원하지 않는 외부의 접근으로부터 변수나 객체 메소드들을 보호한다.
아래는 예시 코드이다.
var Counter = (function() {
var num = 0;
return {
increase() {
return ++num;
},
decrease() {
return --num;
}
};
}());
//즉시실행함수이기 때문에 외부로 노출이 안된다.
console.log(Counter.num); // undefined
console.log(Counter.increase()); //1
console.log(Counter.increase()); //2
console.log(Counter.increase()); //1
console.log(Counter.increase()); //0
캡슐화란?
모듈 패턴은 함수와 클로저를 활용하여 데이터와 기능을 캡슐화한다. 모듈 내부에서 선언된 변수들은 해당 모듈 스코프 내에서만 유효하며, 외부에서 직접 접근할 수 없다. 이를 통해 변수들이 의도치 않게 전역 네임스페이스에 노출되는 것을 방지한다.