자바스크립트 전역변수 #1
프로그래밍 언어를 처음 학습하는 과정에서 자주 볼수 있는 문구가 “전역변수를 사용하지 마라”입니다. 여러가지 이유 때문에 이러한 문구가 제시되겠지만 가장 큰 이유는 사용할 변수를 사용할 범위에만 유효시켜 변수접근에 대해 안정성을 높이고 변수에 대한 메모리 필요한 곳에서만 할당함으로써 메모리 사용에 대한 최적화를 위한것입니다. 또한 전역변수는 모든곳에서 접근가능 하기 때문에 언제 어디서 변경될지 모르는 변수를 쓴다는 것자체가 코드의 가독성을 떨어트리기 때문이기도 합니다(실제로는 이보다 더 많은 이유들이 존재).
그렇다면 자바스크립트의 경우는 어떨까요? 다른언어들과 마찬가지로 자바스크립트 또한 전역변수를 사용하지 않는것이 좋습니다. 하지만 많은 개발자들이 자바스크립트를 사용할 때 전역변수를 사용하는데 여기에는 여러가지 이유(위와 같은 이유겠죠)가 존재하지만 결국 “전역 변수를 사용하지 말아야할 이유”를 못찾기 때문이기도 합니다. 특히나 웹이라는 특성때문에 자바스크립트를 사용할때는 일반 프로그래밍 언어에서 준수해야하는 규칙이 무시되기도 하지만 가장 큰 이유는 전역 변수를 사용하기가 너무 쉽기 때문이기도 합니다. 먼저 자바스크립트에서 전역 변수를 사용하는 예제를 살펴봅시다.
<script>
var element = document.getElementById("div"),
button = document.getElementById("button"),
insertHTML = "<b>Hello world</b>";
button.onclick = function() {
element.innerHTML = insertHTML;
}
</script>
html파일에서 script태그 내에 바로 변수를 선언하면 그것이 전역변수로 지정됩니다. 그럼 이제부터 이처럼 사용하기 쉽고 무의식적으로 사용될 수 있는 자바스크립트의 전역변수에대해 자세히 살펴봅시다.
전역변수를 사용하면 안되는 이유
위에서 “자바스크립트는 웹이라는 특성때문에 전역변수를 그냥 사용한다”라고 명시하였습니다. 실제로는 이와 반대로 웹이라는 특성때문에 더욱더 전역변수의 사용을 조심해야 하는데 웹은 다음과 같은 특성을 갖기 때문입니다.
- 소스와 데이터의 공개성과 다양한 라이브러리를 추가해서사용
- 비동기 로직과 이벤트 기반 처리
- PC 및 모바일 등 컴퓨팅 파워가 다양한 디바이스에서 실행
위 세가지 내용을 좀더 자세히 살펴봅시다. 첫 번째는 보안 및 취약성에 대한 위협이 발생합니다. 서버사이드 자바스크립트(노드js등)가 아닌이상 웹 브라우저(클라이언트)에서 사용되는 자바스크립트는 개발자도구 등을 이용하여 소스 및 사용되는 변수를 볼 수 있습니다. 물론 이렇게 사용되는 자바스크립트는 해킹 등의 위협을 당해도 서버 및 시스템에 치명적인 손상을 주기는 어렵지만 중요하거나 공개하고 싶지 않는 데이터는 전역객체로 사용하지 않는 것이 바람직합니다.
또한 자바스크립트를 사용할 때는 여러가지 외부 라이브러리를 같이 사용합니다. 이때 여러 라이브러리에서 같은 이름의 전역변수를 사용하게 되면 변수가 충돌하게 됩니다. 물론 이런경우는 라이브러리가 잘못되었다고 판단할 수 있지만 충분히 발생할 수 있는 경우이고 여러사람이 같이 개발한 소스를 병합할때 또한 발생할 수 있는 일입니다.
두 번째는 언제 어디서 코드가 실행될지 모른다는 것입니다. 자바스크립트의 경우 순차적으로 실행되는 경우보다 특정 이벤트가 발생하거나 비동기 로직을 통해 코드 실행시점이 정해집니다. 코드의 실행시점을 개발자가 명시적으로 정할 수 없다는 것인데, 이러한 환경에서 전역변수를 사용하게 되면 언제 어디서 해당 변수를 변경하거나 사용할지 알수 없기때문에 예측할 동작을 안할 확률이 높아집니다. 즉 안정성과는 거리가 먼 코드가 작성이 되는 것입니다.
세 번째는 여러가지의 디바이스에서 자바스크립트가 사용된다는 것입니다. 여러가지 디바이스의 경우 디바이스의 크기, 플랫폼 및 브라우저의 종류도 차이가 있지만 결국 성능, 즉 메모리의 크기가 다르기 때문에 웹페이지가 시작 될때 모든 데이터를 메모리에 상주시켜야 되는 전역변수는 성능최적화를 위해 사용하지 않는것이 좋습니다. 특히 전역변수는 가비지 컬렉션의 대상에 포함되지 않을 확률이 높기 때문에(전역변수가 항상 참조하고 있기 때문에) 메모리를 적절히 해제하는 것도 불가능합니다.
전역변수 정의
위에서도 살펴봤지만 자바스크립트는 html에서 script태그안에 바로 변수를 정의하면 전역변수로 정의가 됩니다. 또한 이전의 스코프에 대한 글에서 살펴본것 처럼 다음과 같이 사용해도 전역변수로 정의가 됩니다.
<script>
for(var i=0; i<10; i++) {
var isGlobal = true;
}
</script>
i와 isGlobal모두 전역변수인데, 자바스크립트에서 for구문은 새로운 스코프를 만들어 내지 않기 때문입니다. 그렇다면 다음코드는 위 코드와 같은 코드라고 할 수 있을까요?
<script>
for(i=0; i<10; i++) {
isGlobal = true;
}
</script>
정답은 아니다 입니다. 살펴보면 var선언 여부만 차이나고 실제로 동작은 완전히 동일하게 합니다. 이러한 이유때문에 몇몇 분들은 var를 선언하지 않고 변수를 사용하면 전역변수라고 오해하시는 분들이 있는데 이것은 잘못된 설명입니다. 정확하게 설명하면 var 키워드를 사용하지 않으면 현재보다 상위의 스코프를 탐색한다입니다. 계속해서 상위 스코프로 올라가면서 결국 전역변수로 정의되는 것입니다. 즉 다음과 같은 경우는 changeVariable에서 사용하는 isGlobal이라는 변수는 전역변수가 아니라 func함수의 스코프에 대한 변수 isGlobal을 사용합니다. 상위 스코프를 탐색하는 것이죠.
<script>
var isGlobal = "I'm Global variable";
function func() {
var isGlobal = "is not changed";
changeVariable();
console.log(isGlobal); // "is changed!
function changeVariable(){
isGlobal = "is changed!";
}
}
</script>
window객체
자바스크립트의 전역변수에서 살펴볼 또다른 중요한특징은 글로벌 영역을 window객체가 관장한다는 것입니다. 이 객치는 자바스크립트의 표준에서 Global Object를 의미합니다. Global Object에 대한 설명을 살펴보면 다음과 같습니다.
- 실행 전 단계에 객체가 생성되고,
- 덮어쓸 수는 있으나 루프로 돌 수 없는 기본 내장된 속성을 가지고
- 생성자가 없어서 new로 생성할 수 없고
- 프로토타입(Prototype)도 없고
- HTML DOM환경에서 이 객체는 window 속성을 가지고 있으며 이것이 Global object 그 자체를 나타낸다
라고 정의 되어있습니다. 다음의 예제들을 살펴봅시다.
<script>
var myGlobal = "am i in window?";
var variableName = "myGlobal";
console.log(myGlobal);
console.log(window.myGlobal);
console.log(window["myGlobal"]);
console.log(window[variableName]);
console.log(window == window.window); //true
console.log(window == window.window.window);//true
</script>
전부 같은 결과를 출력합니다. 또한 위 예제의 아래부분과 같이 window는 전역 자체를 나타내므로 window.window.window와 같이 재귀적 특정을 가지게 됩니다.