# 스코프 (Scope)
: 변수와 함수가 접근할 수 있는 유효한 범위
- 코드 내에서 특정 변수나 함수가 어디에서 접근 가능한지를 정의하는 규칙
[ 스코프의 종류 ]
** 변수를 찾는 기준에 따른 분류
" 어떤 기준으로 변수를 찾을까?"
1. 정적 스코프 = 렉시컬 스코프 (Lexical Scope)
: 함수가 선언된 위치(렉시컬 환경)에 따라 스코프(변수의 유효 범위)가 결정되는 방식
- 자바스크립트는 렉시컬 스코프를 따르는 언어로, 함수가 어디서 호출되었는지가 아닌, 어디서 정의되었는지에 따라서 스코프가 결정된다.
- 스코프는 런타임이 아닌 코드 작성 시점에 이미 결정된다.
- 스코프 체인을 통해 자신이 선언된 스코프와 상위 스코프의 변수에 접근할 수 있다.
2. 동적 스코프 (Dynamic Scope)
: 함수가 어디서 호출되었는지(실행 위치)에 따라 스코프가 결정되는 방식
- 실행 시점(runtime)에서의 호출 스택(call stack)을 기준으로 변수를 참조한다.
- 현대 프로그래밍 언어들은 잘 사용하지 않는다.
** 스코프가 적용되는 범위에 따른 분류
"어디까지 접근 가능한가?"
1. 전역 스코프(Global Scope)
: 최상위 스코프로, 코드 어디에서나 접근할 수 있는 범위
- window, globalThis
2. 함수 스코프(Function Scope), 지역 스코프(Local Scope)
: 특정 함수 내에서만 유효한 변수
- 함수 내에서 선언된 변수는 함수 외부에서는 접근할 수 없고 함수 내부에서만 사용 가능
3. 블록 스코프(Block Scope) - {}
: 코드 블록 내에서만 유효한 변수를 의미
- 이 블록은 중괄호 {}로 정의된 영역을 의미
- let, const로 선언된 변수에 해당됨
# 실행 컨텍스트 (Execution Context)
: 자바스크립트 코드가 실행되는 환경
[ 개념 ]
- 자바스크립트 엔진이 코드를 실행하는데 사용하는 내부 메커니즘, 가상의 작업공간
- 코드가 실행될 때 마다 생성되는 환경 정보 객체로, 코드 실행에 필요한 모든 정보(스코프, 변수, this, 호출 스택 등)을 담고 있다.
- 실행 컨텍스트가 스코프 체인을 관리 : 실행 컨텍스트는 활성화될 때 현재 함수의 스코프와 상위 스코프 정보를 스코프 체인으로 저장한다.
[ 구성 요소 ]
- 실행 컨텍스트가 담고있는 코드 실행에 필요한 정보
1. 렉시컬 환경 (Lexical Environment)
- 현재 스코프와 변수/함수 선언 정보 (let/const)
2. 변수 환경 (variable environment)
- 변수의 선언과 초기화 정보 (var)
3. this 바인딩
- 현재 실행 컨텍스트에서의 this 값 관리
4. Scope Chain
- 현재 실행 컨텍스트에서 접근할 수 있는 상위 스코프를 추적하는 체인
- 함수가 호출될 때, 함수 내에서 변수 검색을 하면서 상위 스코프(전역 스코프, 외부 함수 스코프 등)을 검색할 수 있도록 도와준다.
[ 실행 컨텍스트가 하는 일 ]
1. 변수, 함수 선언을 위한 메모리 공간을 만든다.
2. this, 스코프 정보를 저장한다.
3. 코드를 실행할 때 필요한 정보(호출 스택)를 관리한다.
[ 동작 원리 ]
** 콜 스택(Call Stack)
함수가 호출될 때마다 실행 컨텍스트가 콜 스택에 쌓이고, 함수 실행이 끝나면 해당 실행 컨텍스트는 콜 스택에서 제거된다. 콜 스택의 최상단에 있는 실행 컨텍스트가 현재 실행 중인 코드를 관리한다.
- 전역 실행 컨텍스트는 콜 스택의 가장 밑에 위치하며, 모든 코드가 실행되기 위한 기본 환경을 제공한다.
- 함수 실행 컨텍스트는 함수가 호출될 때마다 콜 스택에 쌓이고, 함수 실행이 끝나면 콜 스택에서 제거된다.
[ 분류 ]
- 실행 컨텍스트가 생성되는 경우 3가지
1. 전역 실행 컨텍스트 (global execution context)
- 자바스크립트 코드가 처음 실행될 때 생성
- 어떤 함수도 호출되지 않았을 때 실행되는 최상위 실행 컨텍스트
- 전역객체와 this를 정의한다.
2. 함수 실행 컨텍스트 (function execution context)
- 함수가 호출될 때마다 새로운 실행 컨텍스트가 생성된다.
- 해당 함수에서 실행되는 코드가 이 컨텍스트 안에서 실행된다.
- 함수 내에서 선언된 변수, 매개변수, this, 함수 실행에 필요한 정보 등을 담고 있다.
3. eval 실행 컨텍스트 (eval execution context)
- eval() 함수 내에서 실행되는 코드가 포함된 실행 컨텍스트
- 보안상의 문제로 권장하지 않음
[ 실행 컨텍스트의 중요성 ]
- 호이스팅: 변수와 함수 선언이 실행 컨텍스트 생성 단계에서 먼저 처리되므로, 코드 내에서 변수나 함수를 선언하기 전에 사용할 수 있는 이유는 호이스팅 덕분입니다.
- 스코프 관리: 실행 컨텍스트는 변수와 함수 선언을 관리하며, **스코프 체인(scope chain)**을 설정하여 변수 검색에 필요한 정보를 제공합니다.
- this 바인딩: 함수가 호출될 때마다 **this**가 다르게 바인딩되기 때문에, 실행 컨텍스트는 this가 어떤 객체를 참조하는지를 결정합니다.
[ 실행 컨텍스트 동작 과정 ]
let globalLet = 'Hello World';
function outer() {
let localLet = '지역변수';
console.log(globalLet);
console.log(localLet);
function inner() {
console.log(localLet); // outer의 변수 localLet에 접근 가능 (클로저)
}
return inner;
}
outer();
// Hello World
// 지역변수
// 지역변수
'outer 컨텍스트' : {
VariableEnvironment : { // 자기 자신의 변수 객체
localLet : '지역변수'
},
'scopeChain' : ['outer 변수객체', '전역 변수객체'] // 현재 함수의 scope & 외부 scope 참조 포함
}
- 실행컨텍스트의 스코프 체인으로 outer 함수에서 전역변수에 접근이 가능하다.
- 함수가 호출되면 자바스크립트 엔진은 해당 함수에 대한 새로운 실행 컨텍스트를 생성한다.
ex. outer 함수 실행 => outer context 생성
- 함수의 실행 컨텍스트가 콜스택에 쌓이는 과정 :
함수를 실행하면 호출 스택에 실행 컨텍스트가 순차적으로 하나씩 쌓인다.
global EC => outer() EC => inner() EC
실행이 완료되면 하나씩 제거(pop)되고 global EC는 프로그램이 종료될 때까지 스택에 남아있는다.
[ 용어 정리 ]
# 렉시컬 환경 (Lexical Environment)
: 변수의 유효 범위(스코프)를 정의하는 환경
: 코드가 실행되기 전, 함수를 포함한 변수들이 선언된 시점의 스코프와 그 스코프에서 사용할 수 있는 변수들에 대한 정보를 담고 있는 객체
[ 구성 요소 ]
1. 환경 레코드 (Environment Record) : 현재 스코프 내의 실제 변수와 함수 선언 정보 저장
2. 외부 렉시컬 환경 참조 (Outer Lexical Environment Reference) : 현재 스코프가 참조하는 상위 스코프
# 스코프 체인 (Scope Chain)
: 변수를 찾기 위해 자바스크립트 엔진이 스코프를 따라 올라가며 검색하는 구조
- 특정 변수에 접근하려고 할 때, 현재 스코프에서 찾지 못하면 상위 스코프로 계속 이동하며 변수를 찾는 방식
- 이 과정에서 스코프의 계층 구조를 스코프 체인이라고 한다.
[ 동작 원리 ]
1. 가장 가까운 스코프(현재 스코프)에서 변수를 찾는다 (변수가 선언되었는지 확인한다.)
2. 현재 스코프에서 변수를 찾지 못하면 한 단계 상위 스코프로 이동한다.
3. 계속 상위로 올라가며 전역 스코프에 도달할 때까지 변수 찾기를 반복한다.
- 전역 스코프에서도 변수를 찾지 못하면 ReferenceError가 발생한다.
# 클로저(closure)
: 자바스크립트의 함수가 생성될 때 그 함수가 선언된 환경 (렉시컬 스코프)를 기억하고, 해당 스코프에 접근할 수 있는 기능을 의미
- 내부 함수가 외부 함수의 변수나 실행 컨텍스트에 대한 참조를 유지할 수 있게 해준다.
- 외부 함수의 실행 컨텍스트가 종료되어 콜 스택에서 제거되더라도, 내부함수는 외부함수의 lexical environment에 대한 참조를 유지한다.
- 열린(open) 변수를 닫힌(close) 변수로 만드는 것
[ 동작 원리 ]
1. 자바스크립트의 함수는 렉시컬 스코프를 따르기 때문에 함수가 정의된 위치를 기준으로 스코프가 결정된다.
2. 함수가 생성되면 해당 함수의 렉시컬 환경이 함께 저장된다.
3. 스코프 체인을 통해 내부 함수가 외부 함수의 변수에 접근하면, 클로저는 단순히 접근하는 것에 그치지 않고 상위 함수의 스코프를 기억해서 외부 함수가 종료된 이후에도 그 변수에 접근 가능한 구조를 제공한다.
[ 장점 ]
1. 데이터 보호(캡슐화) : 외부에서 접근할 수 없는 private 변수를 만들 수 있다.
2. 상태 유지 : 특정 함수 호출 이후에도 변수 상태를 유지할 수 있다.
[ 예시 코드 ]
function counter() {
let count = 0; // 함수 내부에서만 접근 가능한 변수
return function () {
count++; // 클로저를 통해 상태 유지 및 업데이트
return count;
};
}
const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
console.log(increment()); // 3
Q. 전역 변수는 왜 메모리 누수를 일으킬까
global EC 는 프로그램이 종료될때까지 스택에 남아있기때문에 전역 변수들도 함께 메모리에 유지된다.
전역변수를 과도하게 사용하면 메모리 사용량을 증가시키고 성능문제가 메모리 누수를 일으킬 수 있다.
- 가능한한 함수내에서 지역변수를 활용할 것
- 관련된 전역 변수를 객체 속성으로 그룹화하여 관리할 것
let globalVar = '전역 변수';
function outer() {
console.log(globalVar);
function inner (){
var innerVar = '내부 함수 변수';
console.log(innerVar);
}
inner();
}
outer();
// 전역 변수
// 내부 함수 변수
'Javascript' 카테고리의 다른 글
[JS] 프로세스, 스레드, 동기, 비동기, 이벤트 루프, 콜 스택, 태스크 큐 ♦︎ (5) | 2024.12.25 |
---|---|
[JS] this (0) | 2024.10.08 |
[JS] BOM, window 객체 사용하기 ♦︎ (0) | 2024.08.02 |
[JS] 이벤트 버블링, 이벤트 캡처링 ♦︎ (0) | 2024.07.05 |
[JS] Javascript 문법적 특징 (1) | 2024.07.01 |