변수는 생성되고 소멸되는 생명 주기가 있다.
만약 생명주기가 없다면 한번 선언된 변수는 프로그램을 종료하지 않는 한
영원히 메모리 공간을 점유하게 될 것이다...
변수는 자신이 선언된 위치에서 생성되고 소멸한다.
하지만 함수내에서 선언된 지역 변수는 함수가 호출되면 생성되고 종료하면 소멸한다.
변수의 생명주기는 메모리 공간이 확보된 시점부터 메모리 공간이 해제되어 가비지 컬렉터에 의해 가용메모리 풀에 반환되는 시점까지다.
그러나 누군가 메모리 공간을 참조하고 있다면 해제되지 않고 메모리 공간이 확보된 상태로 남아있게 된다.
var x = "global";
function foo() {
console.log(x);
var x = "local";
}
foo();
console.log(x);
위 코드를 보면
전역 변수 x는 호이스팅되어 전역 스코프의 선두로 끌어올려진 것처럼 동작한다.
함수 foo내의 지역변수 x는 호이스팅 되어 지역 스코프의 선두로 끌어올려졌다.
즉 호이스팅은 변수 선언이 스코프의 선두로 끌어 올려진 것 처럼 동작하는 것을 말한다.
전역 객체는 코드 실행 이전에 자바스크립트 엔진에 의해 가장 먼저 생성되는 특수한 객체이다.
클라이언트 사이드 환경에서는 window, 서버사이드 환경에서는 global 객체를 의미한다.
전역 객체는 다양한 프로퍼티를 가진다.
1) 표준 빌트인 객체(Object,String...)
2) 환경에 따른 호스트 객체(클라이언트 Web API, Node.js의 호스트API)
3) var 키워드로 선언한 전역변수, 전역함수
(let,const 키워드로 선언한 전역변수,전역함수는 포함x) - 블록 범위를 가지기 때문
1) 암묵적 결합: 전역 변수는 코드 어디서든 참조하고 할당할 수 있기 때문에 모든 코드가 전역 변수를 참조하고 변경할 수 있다.
변수의 유효범위가 클수록 코드의 가독성은 나빠지고 의도치않게 상태가 변경될 수 있는 위험성도 높아진다.
2) 긴 생명주기: 전역 변수는 생명주기가 길다. 따라서 메모리 리소스도 오랜시간 소비한다.
또 전역 변수의 상태를 변경할 수 있는 시간도 길고 기회도 많아진다.
3) 스코프 체인 상에서 종점에 존재: 이는 변수를 검색할때 전역 변수가 가장 마지막에 검색된다는 의미이다. 즉 전역 변수의 검색 속도가 가장 느리다.
검색 속도의 차이가 크지는 않지만 분명히 있다.
4) 네임스페이스 오염
자바스크립트의 가장 큰 문제점중 하나는 파일이 분리되어 있어도 하나의 전역 스코프를 공유한다는 것이다.
따라서 다른 파일내에서 동일한 이름의 전역 변수,함수가 같은 스코프 내에 있으면 오류를 발생시킨다.
전역 변수의 무분별한 사용은 위험하기 때문에 웬만하면 지역변수를 사용하는 것이 좋다.
즉 변수의 스코프는 좁을수록 좋다.
즉시실행함수는 함수를 정의함과 동시에 호출되는 함수이다.
모든 코드를 즉시실행함수로 감싼다면 모든 변수는 즉시실행함수의 지역변수가 될 것이다.
(function () {
var foo = 10;
//...
})();
console.log(foo); // ReferenceError
전역에 네임스페이스 역할을 담당하는 객체를 생성하고 전역변수를 프로퍼티로 추가하는 방법이다.
네임스페이스 객체에 또 다른 네임스페이스 객체를 프로퍼티로 추가해 계층적으로 구성할 수 도 있다.
모듈 패턴을 클래스를 모방해 관련있는 변수와 함수를 모아 즉시실행함수로 감싸 하나의 모듈을 만드는 것이다.
모듈 패턴은 클로저를 기반으로 동작한다. 즉 전역변수를 억제하면서 동시에 캡슐화(은닉화)까지 구현할 수있다.
var Counter = (function () {
var num = 0;
return {
increase: function () {
return num++;
},
decrease() {
return num--;
},
};
})();
console.log(Counter.num);
위 코드에서 Counter는 IIFE(즉시 실행 함수 표현식)를 사용하여 정의된 객체이다.
이 객체는 두 개의 메서드(increase와 decrease)를 포함하고 있으며 외부에 노출되는 public member이다.
num 변수는 IIFE 내부에서만 접근할 수 있는 자유 변수로, 외부에서 접근할 수 없는 private member이다.(정보 은닉)
하지만 Counter 객체의 메서드를 사용하여 num의 값을 증가시키거나 감소시킬 수 있다.
이러한 동작을 캡슐화라고 한다.
자바스크립트는 public,private,protected등의 접근 제한자를 제공하지 않기 때문에 클로저를 기반으로하는 모듈 패턴을 사용하여 대체할 수 있따.
ES6를 사용하면 더이상 전역 변수를 사용할 수 없다.
ES6는 파일 자체의 독자적인 모듈 스코프를 제공한다. 따라서 모듈 내에서 var키워드로 선언한 변수는 더이상 전역변수가 아니다.
<script type="module" scr="lib.mjs"></script>
<script type="module" scr="app.mjs"></script>
스크립트 태그에 type="module" 속성을 추가하면 모든 자바스크립트 파일은 모듈로서 동작한다.