2024. 3. 3. 01:07ㆍ자바스크립트
스코프는 식별자가 유효한 범위를 말한다.
function add(x, y) {
console.log(x, y);
return x + y;
}
add(2, 5);
console.log(x, y); // 참조오류
add 함수의 매개변수인 x,y는 add 함수 내부에서만 유효하다. 유효범위가 add 함수인 것이다.
따라서 add 함수 외부인 전역에서 호출하게 되면 참조 오류가 발생한다.
이것은 유효한 범위에서 호출하지 않았기 때문이다.
let x = 'global';
function foo() {
let x = 'local';
console.log(x);
}
foo();
console.log(x);
위의 코드는 local을 먼저 출력하고 그 다음에 global을 출력한다.
자바스크립트 엔진의 입장에서 한 번 생각해보자.
foo 함수가 호출된다 ➡ foo 함수는 x를 로그에 출력한다 ➡ x를 찾아야한다 ➡ x가 두개다 ➡ 어떻게 x를 찾지?
그래, 자바스크립트 엔진은 어떤 규칙으로 x를 찾는 것일까? 바로 스코프다.
자바스크립트 엔진은 두 개의 x중에 foo 함수를 호출했을 때 어떤 x를 참조해야 하는지 결정해야 하는데 이것을 식별자 결정이라고 한다. 자바스크립트 엔진은 바로 식별자를 검색할 때 스코프라는 규칙을 사용하는 것이다.
(📢 foo의 유효범위에서 x가 있는지 찾아보자...어라! x가 있다. 여기에 참조해야지~)
스코프란 자바스크립트 엔진이 참조의 대상이 되는 식별자(Identifier)를 검색할 때 사용하는 규칙의 집합 이다.
스코프 체인
const x = 1;
const y = 2;
const a = 'HELLO';
function outer() {
const x = 10;
const y = 20;
const z = 30;
function inner() {
const x = 100;
const y = 200;
console.log(x, y);
console.log('z', z);
console.log('a', a);
}
inner();
console.log(x, y);
}
outer();
console.log(x, y);
inner 함수가 호출될 때 z와 a를 출력해야한다. 그런데 inner 함수 내부에는 z와 a가 없다.
하지만 inner 함수는 outer 함수 내부에 정의된 z, 전역 스코프에 정의된 a에 참조해 그 값들을 출력하고 있다.
이것이 가능한 이유가 바로 스코프 체이닝 때문이다.
말 그대로 스코프들끼리 체이닝이 되어있다는 것이다. 그림으로 표현해보자.
먼저 자신의 스코프에서 식별자를 찾고 없다면 화살표 방향으로 상위 스코프에서 찾는다.
inner 함수에 z식별자를 찾을 수 없으므로 그 상위 스코프인 outer 함수의 스코프로 간다.
outer 함수에서는 z식별자를 찾을 수 있다. 따라서 inner 함수에서 z의 식별자를 결정해 출력할 수 있는 것이다.
변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
단, 주의할 점은 화살표의 방향이다. 아래에서 위로 갈 순 있지만 위에서 아래로는 못내려온다.
즉, 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조할 수 있지만 하위 스코프에서 유효한 변수를 상위 스코프에서 참조할 수 없다.
렉시컬 스코프
정적 스코프라고도 부른다. 자바스크립트는 렉시컬 스코프를 따르는 언어이다.
const x = 1;
function foo() {
const x = 10;
bar();
}
function bar() {
console.log(x);
}
foo();
bar();
첫번째 foo를 호출하는 것부터 살펴보자.
foo를 호출하고 foo내부에서 bar를 호출한다. bar는 x를 출력해야하는데 bar에는 x가 존재하지 않는다.
따라서 bar는 상위 스코프에서 x를 찾아야한다.
그렇다면 bar의 상위 스코프는 어디인가? 두가지 선택지가 있다. 하나는 전역, 하나는 foo이다.
bar가 호출된 위치를 기준으로 한다면 foo가 bar의 상위 스코프일 것이다.
하지만 bar가 정의된 위치를 기준으로 한다면 bar의 상위 스코프는 전역 스코프이다.
렉시컬 스코프라면 함수가 정의된 위치를 기준으로 상위 스코프가 결정이 된다.
함수가 호출된 위치는 상위 스코프를 결정하는 것에 어떠한 영향을 주지 않는다.
이처럼 상위 스코프는 함수 정의가 실행될 때 정적(Lexical)으로 결정된다. (클로저의 냄새가 난다)
렉시컬 스코프는 함수 정의가 평가되는 시점에 상위 스코프가 정적으로 결정된다.