JavaScript

JavaScirpt 변수

Dev.JH 2023. 4. 3. 17:58

1. 변수의 생명주기

변수 선언은 선언문이 어디에 있든 상관없이 가장 먼저 실행된다. 다시 말해, 변수 선언은 코드가 한 줄씩 순차적으로 실행되는 런타임에 실행되는 것이 아니라 런타임 이전 단계에서 자바스크립트 엔진에 의해 먼저 실행 된다. 그러나 엄밀히 말하자면 위 설명은 전역 변수에 한정된 것이다. 함수 내부에서 선언한 변수는 함수가 호출된 직후에 함수 몸체의 코드가 한 줄씩 순차적으로 실행되기 이전에 자바스크립트 엔진에 의해 먼저 실행된다.

function foo() {
    var x = 'local';
    console.log(x);
    return x;
}

foo();
console.log(x); // ReferenceError

따라서 위 예제를 보면 foo함수를 호출하면 x변수가 선언되고 undefined로 초기화된다. 그 후, 함수 몸체를 구성하는 문들이 순차적으로 실행되기 시작하고 변수 할당문이 실행되면 x변수에 값이 할당된다. 그리고 x 변수도 소멸되어 생명주기가 종료된다. 즉, 지역 변수의 생명주기는 생명주기와 일치한다.

호이스팅은 스코프를 단위로 동작한다. 즉 호이스팅은 변수 선언이 스코프의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 말한다. var 키워드로 선언한 전역 변수는 전역 객체 window의 프로퍼티이다. 전역 객체 window는 웹페이지를 닫기 전까지 유효하고, var키워드로 선언한 전역 변수의 생명 주기는 전역 객체의 생명주기와 일치한다.

2. 전역 변수의 문제점

지금까지 전역변수의 특징들에 대해서 알아보았는데, 그럼 전역 변수가 왜 문제인지에 대해서 살펴보자. 전역변수는 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합 을 허용한다.

1. 긴 생명주기 -> 메모리 리소스를 오랜 기간 소비한다. 또한 변수 이름이 중복되어 재할당이 이루어질 수 있다.

2. 스코프 체인 상에서 종점에 존재 -> 전역 변수는 스코프 체인 상에서 종점에 존재한다. 따라서 가장 마지막에 검색된다. 검색속도가 가장 느리다는 이야기이다.

3. 네임스페이스 오염 -> 파일이 분리되어 있어도 하나의 전역 스코프를 공유한다. 따라서 다른 파일 내에서 동일한 이름으로 명며왼 전역 변수나 전역 함수 같은 스코프 내에 존재하면 문제가 발생한다.

3. 전역 변수의 사용을 억제하는 방법

전역변수 보다는 되도록 지역 변수를 사용해야 하며, 변수의 스코프는 좁을수록 좋다.

1. 즉시 실행 함수

모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다. (function(){ var foo = 10; })

console.log(foo); // ReferenceError

2. 네임스페이스 객체

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

var MYAPP = {}; //전역 네임스페이스 객체

MYAPP.name = 'Lee';

console.log(MYAPP.name); //Lee

네임스페이스 객체 자체가 전역 변수에 할당되므로 그다지 유용해 보이지는 않는다.

3. 모듈 패턴

캡슐화는 객체의 상태를 나타내는 프로퍼티와 메서드를 하나로 묶는 것을 말한다. var Counter = (function () { //즉시실행함수로 감싼다 // private 변수 var num = 0;

// 클로저 //외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환한다. return { increase() { return ++num; }, decrease() { return --num; } }; }());

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

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

Counter는 값으로 담고 있는 프로퍼티들을 담은 객체를 반환하고 있다. Counter의 스코프 밖에서 바라볼 때 Counter의 그 어떠한 프로퍼티에도 접근을 할 수 없다. 즉시실행함수는 한 번만 실행되므로 Counter가 호출될 때마다 num 변수가 초기화될 일은 없다. 즉시실행함수가 반환한 클로저는 Counter 변수에 할당되어 호출된다. 이 때 이 클로저는 자신이 정의된 위치에 의해 결정된 상위 스코프인 즉시실행 함수의 렉시컬 스코프를 기억하고 있어서 카운트 상태를 유지하기 위해 변수 num을 참조하고 변경할 수 있다.