![[JavaScript] 스코프 체인 (scope chain)](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnBQ9r%2FbtsL1elcQcR%2F0kR3PD3wiCj8M6QJG7JR51%2Fimg.jpg)
들어가며
자바스크립트에서 스코프 체인은 변수와 함수의 유효 범위를 결정한다. 이 글에서는 스코프 체인이 무엇이고 어떻게 동작하는지를 이해해보려 한다. 스코프 체인에서 변수를 찾는 과정은 단방향으로 이루어진다. 자바스크립트 엔진은 현재 스코프에서 시작해 상위로 올라가면서 변수를 찾아간다. 결과적으로 스코프가 변수와 함수의 접근성을 단순하고 일관된 규칙으로 관리하는 것을 이해할 수 있을 것이다.
스코프 체인
함수는 전역이나 다른 함수 내부에서 정의할 수 있다. 함수 내부에 다른 함수를 정의하는 것을 함수의 중첩이라 하며, 이때 내부에 정의된 함수를 중첩 함수$_{nested \space function}$, 이를 감싸는 함수를 외부 함수$_{outer \space function}$라 한다.
함수가 중첩되면 각 함수의 지역 스코프도 중첩된다. 스코프가 함수의 중첩에 따라 계층적 구조를 형성한다는 뜻으로 생각하면 된다. 중첩 함수의 지역 스코프는 자신을 감싸는 외부 함수의 지역 스코프와 계층 구조를 이루고 이때 외부 함수의 지역 스코프를 중첩 함수의 상위 스코프라 한다.
예를 들어 outer 함수 안에 inner 함수가 정의된 경우, 두 개의 지역 스코프가 생성된다. inner 함수는 outer 함수의 중첩 함수이므로, outer 함수의 지역 스코프는 inner 함수 지역 스코프의 상위 스코프가 된다. 또한 outer 함수의 지역 스코프는 전역 스코프를 자신의 상위 스코프로 갖는다. 이런 계층 구조를 시퀀스 다이어그램으로 나타내면 아래와 같다.
이처럼 모든 스코프는 하나의 계층 구조로 연결되고 전역 스코프가 최상위가 된다. 이렇게 스코프가 계층적으로 연결된 것을 스코프 체인$_{scope \space chain}$이라 한다. 위 시퀀스 다이어그램의 스코프 체인은 전역 스코프를 시작으로 outer 함수의 지역 스코프, 그리고 inner 함수의 지역 스코프로 이어진다.
식별자 결정
자바스크립트 엔진은 변수를 찾을 때 이 스코프 체인을 따라 움직인다. 변수가 참조되면 현재 스코프에서 시작해 상위 스코프 방향으로 이동하며 변수를 식별자 결정$_{identifier \space resolution}$한다. 이런 구조 덕분에 하위 스코프에서 상위 스코프의 변수를 참조할 수 있다.
자바스크립트 엔진은 코드 실행 전에 스코프 체인을 렉시컬 환경이라는 자료구조를 생성한다. 변수가 선언되면 이 자료구조에 식별자가 등록되고, 할당이 일어나면 해당 식별자의 값이 변경된다. 변수 검색도 이 자료구조를 통해 이루어진다.
렉시컬 환경$_{lexical \space environment}$
스코프 체인은 자바스크립트 엔진에서 '렉시컬 환경'이라는 자료구조로 구현된다.
렉시컬 환경은 두 가지 구성 요소를 가진다.
> 환경 레코드, 스코프 내의 식별자와 값을 기록하는 객체
> 외부 렉시컬 환경에 대한 참조, 상위 스코프의 렉시컬 환경을 가리키는 참조
예를 들어 함수를 실행하면 새로운 렉시컬 환경이 생성된다. 이 환경의 환경 레코드에는 함수의 매개변수와 지역 변수들이 기록되고, 외부 환경 참조는 함수가 선언된 시점의 상위 스코프를 가리킨다.
스코프 체인에 의한 변수 식별자 결정
const y = 1;
function outer() {
const z = 2;
function inner() {
const x = 3;
console.log(x); // inner 지역 스코프에서 x를 찾음
console.log(y); // 전역 스코프에서 y를 찾음
console.log(z); // outer 지역 스코프에서 z를 찾음
}
inner();
}
outer();
자바스크립트 엔진이 변수를 찾는 과정을 하나씩 살펴보자. 먼저 x 변수를 찾을 때는 현재 스코프인 inner 함수 내부에서 바로 찾을 수 있다. x가 inner 함수에 선언되어 있기 때문에 더 이상의 검색 없이 이 변수를 사용한다.
y 변수는 조금 다른 과정을 거친다. inner 함수에서 시작해 y를 찾지만 없다. 그래서 outer 함수 스코프로 이동하는데 여기서도 찾지 못한다. 결국 전역 스코프까지 올라가서 y를 찾게 된다.
z 변수는 중간에서 찾는다. inner 함수에서 z를 찾기 시작해 없으니 outer 함수 스코프로 이동한다. 여기서 z를 찾았으므로 검색을 멈춘다.
이처럼 자바스크립트 엔진은 스코프 체인을 따라 순차적으로 변수를 찾아 올라간다. 아래에서 위로만 움직이며, 절대 다시 아래로 내려가지 않는다. 마치 부모와 자식 관계처럼 자식은 부모의 것을 쓸 수 있지만, 부모는 자식의 것을 쓸 수 없는 것과 같다. 객체 지향의 상속$_{inheritance}$과 비슷한 이 개념이 스코프 체인의 핵심이다.
스코프 체인에 의한 함수 식별자 결정
const x = 1;
function outer() {
const x = 10;
function inner() {
const x = 100;
console.log(x); // inner의 x를 참조
console.log(outer); // outer 함수를 참조
}
inner();
}
outer();
함수도 변수처럼 식별자로 관리된다. 함수 선언문으로 함수를 정의하면 자바스크립트 엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고, 여기에 함수 객체를 할당한다. 이 과정은 코드가 실행되기 전인 런타임 이전에 이루어진다.
위 예제에서 outer 함수를 호출할 때, 자바스크립트 엔진은 먼저 변수를 찾을 때와 동일한 방식으로 outer라는 식별자를 찾는다. 그 후, 현재 스코프에서 시작해 상위 스코프로 이동하며 검색한다.
이처럼 함수는 '함수'라는 점 외에는 일반 변수와 동일하게 취급된다. 따라서 스코프는 단순히 '변수를 검색하는 규칙'이 아닌 '식별자를 검색하는 규칙'이라고 이해하는 것이 더 정확하다.
references
https://www.yes24.com/Product/Goods/92742567
https://ui.toast.com/weekly-pick/ko_20171006#newfunctionenvironment
'Web, Front-end > JavaScript' 카테고리의 다른 글
[JavaScript] 이벤트 루프(Event Loop)와 비동기 통신 (1) | 2025.02.01 |
---|---|
[JavaScript] 함수 레벨 스코프와 블록 레벨 스코프 (1) | 2025.01.30 |
[JavaScript] 스코프(scope)란 (0) | 2025.01.25 |
[Javascript] 이벤트 전파 (1) | 2024.08.27 |
[Javascript] 이벤트 핸들러 등록 (0) | 2024.08.27 |
컴퓨터 전공 관련, 프론트엔드 개발 지식들을 공유합니다. React, Javascript를 다룰 줄 알며 요즘에는 Typescript에도 관심이 생겨 공부하고 있습니다. 서로 소통하면서 프로젝트 하는 것을 즐기며 많은 대외활동으로 개발 능력과 소프트 스킬을 다듬어나가고 있습니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!