📗스코프

Scope란, 우리가 작성하는 코드의 접근 범위를 결정하는 개념입니다.

예제 코드부터 바로 볼까요?

function logSomething () {
  const a = 1;
  console.log(a);
}

logSomething();  // 정상 출력
console.log(a);  // 오류 발생

위 예시에서 마지막 줄의 실행문은 오류를 발생시킵니다. 그 원인이 바로 스코프 즉, 코드의 접근 범위에 대한 규칙 때문입니다. 🙂 스코프라는 개념에 대해 알게 된다면, 현재 발생한 오류에 대해 정확히 이해할 수 있습니다.

조금 다른 예제를 볼까요? 아래와 같은 예제 코드에서는 어떤 값이 콘솔에 출력될까요?

const a = 10;

function foo () {
  const a = 1;
  
  console.log(a);
}

foo();

1이 출력될까요? 10이 출력될까요? 이 또한 스코프에 대한 개념을 이해한다면, 이 코드의 결과를 정확히 예측할 수 있습니다.

스코프와 스코프 체인

변수의 스코프란, 변수를 감싸고 있는 가장 가까운 중괄호 블록을 의미합니다.

몇 가지 예시를 볼까요?

위 예시에서 a 변수를 감싸고 있는 가장 가까운 중괄호 블록은 if 조건문이기 때문에, 빨간 영역이 a 변수의 스코프입니다.

다음과 같이 조건문이 중첩되어 내부에 추가된다 하여도, a 변수의 스코프는 변함이 없습니다. 왜냐하면, a 변수를 감싸고 있는 가장 가까운 중괄호 블록이 a 변수의 스코프이기 때문입니다.

만약 위와 동일한 코드에서 b 변수의 스코프는 무엇일까? 라고 질문을 바꿔본다면, 답은 달라집니다. b 변수가 선언된 곳을 감싸고 있는 가장 가까운 중괄호 블록은 아래와 같습니다.

우리가 어떤 변수를 사용했을때, 자바스크립트에서는 아래와 같은 규칙에 따라 변수를 찾는 과정이 진행됩니다.

  1. 변수를 사용한 위치의 스코프 내에서 변수가 선언된 구문이 있는지 찾습니다.

  2. 만약 있다면, 해당 변수의 값을 사용하고, 찾는 과정이 종료됩니다.

  3. 만약 없다면, 상위 스코프에서 변수가 선언된 구문이 있는지 찾습니다.

  4. 만약 있다면, 해당 변수의 값을 사용하고, 찾는 과정이 종료됩니다.

  5. 최상단 스코프까지 이런 탐색 과정이 반복됩니다.

아래에서 조금 더 자세히 설명하겠지만, 위와 같은 과정을 스코프 체인이라고 합니다.

상위 스코프와 하위 스코프라는 것은 위의 예시 코드에서 본 중첩된 조건문과 유사한 상황입니다.

예시 1번

아래 코드를 한번 살펴보세요.

Example 1
const a = 1;

function foo () {
  console.log(a); // 로그 #1
}

foo();

실행 순서

  1. 1번줄) 변수 a를 선언하고 1이라는 숫자값을 해당 변수에 할당합니다.

  2. 3-5번줄) 함수 foo를 생성합니다. (foo라는 단어는 이제 이 함수를 가르키게 됩니다.)

  3. 7번줄) 함수 foo를 실행합니다. foo 함수 내부 코드가 실행됩니다.

  4. 4번줄) a를 출력합니다.

    • 변수 a의 값을 출력하기 위해 a라는 변수의 값을 찾습니다.

    • 현 실행문(console.log(a);)와 같은 중괄호 블록 범위인 foo 함수 스코프 내부(3-5번줄 사이)에서 먼저 a라는 변수를 찾습니다만, a 변수가 선언된 구문을 찾지 못합니다.

    • foo 함수 스코프에서 한 단계 상위 스코프로 올라가서 a라는 변수가 선언된 구문을 찾습니다.

    • 1번줄에서 a라는 변수가 선언된 것을 찾고, 그에 해당하는 값인 1을 사용합니다.

    • a의 값인 1을 출력하게 됩니다.

  5. 4번줄) foo 함수의 실행이 종료됩니다.

  6. 7번줄) foo 함수 실행문의 종료를 끝으로 우리 프로그램도 종료됩니다.

스코프 체인

아래 이미지 내부 코드는 var 라는 변수 선언문이 사용되었지만, 기본 원리는 동일합니다.

스코프란 위 그림처럼 계층 구조로 형성됩니다.

어떤 함수나 블록으로도 둘러싸여 있지 않은 가장 최상위 스코프는 글로벌 스코프라고 부릅니다.

그리고 그 하위엔 함수나 블록 생성을 기준으로 하위 스코프가 생성됩니다.

위 그림에서는 가장 최상위에 글로벌 스코프가 존재하고, 그 하위에 Person 함수 스코프가 존재하고, Person 함수 스코프 내부에 displayName이라는 함수의 스코프가 존재합니다.

이런 스코프 계층에서 가장 중요한 특징은, 변수 탐색은 항상 하위에서 상위 계층의 방향으로 진행된다는 점입니다. 실행문이 위치한 스코프부터 시작하여 원하는 값을 찾을때까지 상위 스코프로 탐색을 진행합니다.

추가 예제와 함께 더 자세히 살펴보도록 하겠습니다.

예시 2번

Example 2
const a = 1;

function foo () {
  const a = 2;
  console.log(a); // 로그 #1
}

foo();

위 예제에서 5번줄의 콘솔 메시지는 어떤 값을 출력할까요?

어떤 변수에 대한 값을 탐색할때 자바스크립트는 현 실행문이 위치한 스코프부터 시작하여 해당 변수의 값을 찾아나갑니다.

실행 순서

  • 5번줄에서 a라는 메시지를 출력하는 실행문이 실행됩니다.

  • 현 실행문의 위치는 5번줄입니다. 즉, foo 함수 스코프 내부에서 시작하여 해당 변수를 찾기 위한 탐색이 시작됩니다.

  • foo 함수 스코프 탐색 결과, 4번줄에 있는 (값이 2인) a 변수를 찾습니다.

  • 5번줄의 콘솔 출력문은 2를 출력합니다.

예시 3번

Example 3
const a = 1;

function foo () {
  const a = 2;
  console.log(a); // 로그 #1
}

foo();
console.log(a);   // 로그 #2

위 예제에서 5번줄과 9번줄의 콘솔 메시지는 어떤 값을 출력할까요?

실행 순서 - 5번줄

  • 예시 2번과 동일한 이유로 2가 출력됩니다.

실행 순서 - 9번줄

  • 현재 실행문의 위치는 글로벌 스코프입니다. 자바스크립트는 글로벌 스코프를 시작점으로 하여 a 변수의 위치를 찾습니다. (더 이상 탐색할 상위 스코프는 존재하지 않습니다.)

  • 1번줄에 a 변수가 선언되어 있음을 찾고, 1이라는 값임을 알게 됩니다.

  • 9번줄의 콘솔 메시지는 1을 출력하게 됩니다.

예시 4번

Example 4
function foo () {
  const a = 2;
  console.log(a); // 로그 #1
}

foo();
console.log(a);   // 로그 #2

위 예제에서 3번줄과 7번줄의 콘솔 메시지는 어떤 값을 출력할까요?

실행 순서 - 3번줄

  • 예시 2, 3번과 동일한 이유로 숫자 2가 출력됩니다.

실행 순서 - 7번줄

  • 현재 실행문의 위치는 글로벌 스코프입니다. 그리하여 자바스크립트는 글로벌 스코프를 시작점으로 하여 a 변수의 위치를 찾습니다. (더 이상 탐색할 상위 스코프는 존재하지 않습니다.)

  • 글로벌 스코프에서 a 변수가 존재하는지 찾지만, 찾을 수 없습니다.

  • 자바스크립트 입장에서 a라는 명칭은 알 수 없는 문자입니다. 결국 오류가 발생하게 됩니다.

7번줄의 실행문은 글로벌 스코프에서 실행되었기 때문에 상위 스코프가 존재하지 않습니다.

변수를 선언할때, 해당 변수가 사용되는 스코프를 잘 판단하여 불필요하게 상위 스코프에 선언하지 않도록 해야 합니다.

Last updated