- 변수는 선언에 의해 생성되고 할당을 통해 값을 갖는다. 변수에 생명 주기가 없으면 한 번 선언된 변수는 프로그램 종료하지 않는 한 영원히 메모리 공간을 점유한다.
- 전역 변수의 생명 주기 == 애플리케이션의 생명 주기 지역 변수의 생명 주기 == 함수가 호출될 때부터 종료될 때까지
변수의 생명 주기는 메모리 공간이 확보된 시점부터 메모리 공간이 해제되어 가용 메모리 풀에 반환되는 시점까지다.
호이스팅은 스코프를 단위로 동작한다.
- 전역 변수의 호이스팅은 전역 변수의 선언이 전역 스코프의 선두로 끌어 올려진 것처럼 동작한다.
- 지역 변수의 호이스팅은 지역 변수의 선언이 지역 스코프의 선두로 끌어 올려진 것처럼 동작한다.
전역 코드는 함수 호출과 같이 전역 코드를 실행하는 진입점(프로그램이 시작되는 지점)이 없고 코드가 로드되자마자 바로 실행된다. 함수는 함수의 몸체의 마지막 문 또는 반환문이 실행되면 종료된다. 전역 코드에서는 반환문을 사용할 수 없으므로 마지막 문이 실행되어 더 이상 실행할 문이 없을 때 종료한다.
var 키워드로 선언한 전역 변수의 생명 주기는 전역 객체의 생명 주기와 일치한다.
❓ 전역 객체: 코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체
- 클라이언트 사이드 환경(브라우저)에선
window, 서버 사이드 환경(Node.js)에선global객체- 환경에 따라 전역 객체를 가리키는 식별자 => globalThis
- 표준 빌트인 객체(Object, String, Number, Function, Array)와 환경에 따른 호스트 객체(API) 그리고 var로 선언한 전역 변수와 전역 함수를 프로퍼티로 갖는다. (프로퍼티란? 객체 지향 프로그래밍 언어에서 클래스 멤버의 일종으로, 속성이나 상태를 의미)
**1. 암묵적 결합: **
- 전역 변수를 선언하는 의도는 모든 코드가 참조하고 변경할 수 있는 암묵적 결합을 허용하는 것을 의미한다.
- 변수의 유효 범위가 클수록 가독성은 낮아지고 상태 변경 위험도가 높아진다.
**2. 긴 생명 주기: **
- 전역 변수는 생명 주기가 길어 메모리 리소스도 오랜 기간 소비한다.
- 전역 변수는 변수 이름이 중복될 가능성이 높아 의도치 않은 재할당이 이뤄진다.
3. 스코프 체인 상에서 중점에 존재
- 전역 변수는 스코프 체인 상에서 종점에 존재한다. => 변수를 검색할 때 전역 변수가 가장 마지막에 검색된다.
- JS에서 변수를 검색하는 과정은 스코프 체인을 따라 이뤄짐.
- 각 함수는 자신이 선언된 스코프의 변수에 접근할 수 있도록 체인을 형성하는데 이를 스코프 체인이라고 한다.
[ 스코프 체인의 작동 방식 ] 1. 현재 실행 중인 함수의 스코프에서 변수를 찾는다. 2. 찾지 못하면 상위 스코프(부모 함수)로 이동하여 변수를 찾는다. 3. 계속 상위 스코프로 이동하며 찾는다. 4. 가장 상위 스코프(전역 스코프)까지 도달했는데도 없으면
ReferenceError가 발생한다.
let globalVar = "I am global";
function first() {
function second() {
console.log(globalVar); // second → first → 전역에서 찾음
}
second();
}
first();=> 만약 변수가 전역에서만 선언되어 있다면, 스코프 체인을 따라 전역까지 검색한 후에야 찾을 수 있습니다.
4. 네임스페이스 오염
- 자바스크립트 내에서는 하나의 전역 스코프를 다른 파일에서도 공유한다. => 다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 스코프의 경우 예상치 못한 결과를 불러일으킴.
함수 정의와 동시에 호출되는 즉시 실행 함수는 단 한 번만 호출된다. 모든 코드를 즉시 실행 함수로 감싸면, 모든 변수는 즉시 실행 함수의 지역 변수가 된다.
let message = "Global Scope";
(function () {
let message = "IIFE Scope";
console.log(message); // "IIFE Scope"
})();
console.log(message); // "Global Scope"=> message 변수가 전역과 IIFE 내부에서 각각 다른 값으로 선언되었기 때문에, 전역 스코프를 보호할 수 있음.
전역에 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법
var MYAPP = {}; // 전역 네임스페이스 객체
MYAPP.name = "Lee";
console.log(MYAPP.name); // Lee모듈 패턴은 관련 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모둘을 만든다. 모듈 패턴은 클로저 기반으로 동작하여, 전역 변수의 억제를 캡슐화까지 구현할 수 있다.
클로저: 내부 함수에서 외부 함수의 범위에 대한 접근을 제공 캡슐화: 비슷한, 관련된 역할을 하는 속성과 메소드들을 하나의 틀(클래스 등) 안에 담는 것을 의미
캡슐화(Encapsulation) 를 위해 변수를 외부에서 직접 접근하지 못하도록 만드는 여러 가지 방법이 있습니다.
function Counter() {
let count = 0; // private 변수
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count,
};
}
const counter = Counter();
console.log(counter.getCount()); // 0
console.log(counter.increment()); // 1
console.log(counter.getCount()); // 1
console.log(counter.count); // undefined (외부에서 직접 접근 불가)✅ count는 Counter 함수 내부에서만 존재하며, 반환된 객체를 통해서만 접근 가능 → 완전한 private 변수
- ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공한다.
- import와 export를 사용하여 코드를 분리하는 방식입니다.
모듈 스코프란? 각각의 모듈이 자체적인 스코프를 가지며, 전역 스코프(global scope)를 오염시키지 않는 것을 의미합니다.
- 모듈 내부에서 선언된 변수는 export하지 않는 한 외부에서 접근할 수 없음.
// 📂 `counter.js`
let count = 0; // 모듈 내부 변수 (외부에서 접근 불가)
export const increment = () => ++count;
export const getCount = () => count;
// 📂 `main.js`
import { increment, getCount } from "./counter.js";
console.log(getCount()); // 0
increment();
console.log(getCount()); // 1
console.log(count); // ❌ ReferenceError (count는 모듈 스코프 내에 있음)`- 이전의 var처럼 window 객체에 등록되지 않음.
// 📂 global.js (일반 JS 파일)
var globalVar = "I am Global";
console.log(window.globalVar); // "I am Global"
// 일반적인 JS 파일에서는 var로 선언된 변수는 window 객체에 등록됨
// 📂 module.js (ES6 모듈 파일)
export const moduleVar = "I am in Module";
import { moduleVar } from "./module.js";
console.log(window.moduleVar); // undefined (모듈 스코프 때문에 전역 객체에 등록되지 않음)- import / export를 사용해야만 모듈 간 데이터 공유 가능.

