본문 바로가기
JAVASCRIPT

[JS][스코프] 중첩 스코프 와 오류, 정리하기

by KBS 2022. 2. 15.
728x90

중첩 스코프

스코프는 확인자 이름으로 변수를 찾기 위한 규칙의 집합이라고 앞서 말한 바 있다. 그러나 대개 고려해야할 스코프는 여러개다.

하나의 블록이나 함수는 다른 블록이나 함수안에 중첩될 수있으므로 스코프도 다른 스코프안에 중첩될 수있다. 따라서 대상 변수를 현재 스코프에서 발견하지 못하면 엔진은 다음 바깥의 스코프로 넘어가는 식으로 변수를 ㅊ자거나 글로벌 스코프라 부르는 가장 바깥 스코프에 도달할 때까지 계속한다.

function foo(a) {
  console.log(a + b);
}

var b = 2;

foo(2); // 4

 

b에 대한 RHS 참조는 함수 foo안에서 처리할 수 없고, 함수를 포함하는 스코프에서 처리한다.

엔진과 스코프의 대화를 다시보자.

  • 엔진 : 이봐 foo 스코프, b에 대해 들어본적 있니? b에 대한 RHS 참조가 필요한데 말이야
  • 스코프 : 아니 못들어봤어. 딴 데 가봐
  • 엔진 : 이봐 foo의 바깥 스코프! 아, 네가 글로벌 스코프구나. 혹시 b에 대해 들어봤니? b에 대한 RHS 참조가 필요해
  • 스코프 : 응 물론들어봤지, 여기있어

중첩 스코프를 탐사할 때 사용하는 간단한 규칙은 다음과 같다.

  • 엔진은 현재 스코프에서 변수를 찾기 시작하고, 찾지 못하면 한 단계씩 올라간다.
  • 최상위 글로벌 스코프에 도달하면 변수를 찾았든, 못 찾았든 검색을 멈춘다.

비유

중첩 스코프 검색 과정을 큰 빌딩으로 생각해보자.

이 빌딩은 프로그램의 중첩 스코프 규칙 집합을 나타낸다. 어디에 있든 1층은 현재 실행 중인 스코프를 뜻한다. LHS/RHS를 참조하려면 현재 층을 둘러보고, 찾지 못하ㅕㄴ 엘리베이터를 타고 다음층으로 가서 찾고, 또 다음 층으로 이동하는 식이다. 최상위 층(글로벌 스코프)에 도달했을때 찾았건, 못 찾았건 검색은 거기서 중단한다.

오류

LHS와 RHS를 구분하는 것이 왜 중요할까? 이 두 종류의 검색 방식은 변수가 아직 선언되지 않았을 때(검색한 모든 스코프에서 찾지 못했을때) 서로 다르게 동작한다.

function foo(a) {
  console.log(a + b);
}

foo(2);

 

b에 대한 첫 RHS 검색이 실패하면 다시는 b를 찾을 수 없다. 이렇게 스코프에서 찾지 못한 변수는 '선언되지 않은 변수'라 한다. RHS 검색이 중첩 스코프 안 어디에서도 변수를 찾지 못하면 엔진이 'ReferenceError'를 발생시킨다. 여기서 중요한 점은 발생된 오류가 ReferenceError 타입이란 점이다.

반면에, 엔진이 LHS 검색을 수행하여 변수를 찾지 못하고 최상위 층(글로벌 스코프)에 도착할 때 프로그램이 'Strict Mode'로 동작하는 것이 아니라면, 글로벌 스코프는 엔진이 검색하는 이름을 가진 새로운 변수를 생성해서 엔진에게 넘겨준다. 즉, "없어, 없었지만 내가 널 위해 하나 만들어주지"라고 생각하면 된다.

ES5부터 지원하는 'Strict Mode'는 Normal/Relaxed/Lazy Mode와는 여러 면에서 다르게 작동한다. 예를 들어, Strict Mode에서는 글로벌 변수를 자동으로 또는 암시적으로 생성할 수 없다. 그래서 앞의 상황이 닥치면 글로벌 스코프는 변수를 생성하지 않아서 LHS 검색은 아무 것도 얻지 못하고, 엔진은 RHS의 경우와 비슷하게 ReferenceError를 발생시킨다.

이제, RHS 검색 결과 변수를 찾았지만 그 값을 가지고 불가능한 일을 하려고 할 경우를 보자.

예를들어 함수가 아닌 값을 함수처럼 실행하거나 null이나 undefined값을 참조할 때 엔지은 TypeError를 발생시킨다.

ReferenceError는 스코프에서 대상을 찾았는지와 관계있지만, TypeError는 스코프 검색은 성공했으나 결괏값을 가지고 적합하지 않거나 불가능한 시도를 한 경우를 의미한다.

 

정리하기

스코프는 어디서 어떻게 변수를찾는가를 결정하는 규칙의 집합이다. 변수를 검색하는 이유는 변수에 값을 대입하거나 변수의 값을 얻어오기 위해서다.

LHS 참조는 대입 연산 과정에서 일어난다. 스코프와 관련된 대입 연산은 '='연산자가 사용되거나 인자를 함수의 인자로 넘겨줄 때 일어난다.

자바스크립트 엔진은 코드를 실행하기 전에 먼저 컴파일하는데, 이 과정에서 엔진은 var a = 2;와 같은 구문을 독립된 두 단계로 나눈다.

  1. var a는 변수 a를 해당 스코프에 선언한다. 이 단계는 코드 실행 전에 처음부터 수행된다.
  2. a = 2는 변수 a를 찾아 값을 대입한다.(LHS)

LHS와 RHS 참조 검색은 모두 현재 실행 중인 스코프에서 시작한다. 그리고 필요하다면(대상 변수를 찾지 못했을 경우) 한 번에 한 스코프씩 중첩스코프의 상위 스코프로 넘어가며 확인자를 찾는다. 이 작업은 글로벌 스코프에 이를 때까지 계속하고 대상을 찾았든, 못 찾았든 작업을 중단한다.

RHS 참조가 대상을 찾지 못하면 ReferenceError가 발생한다. LHS 참조가 대상을 ㅈ찾지 못하면 자동적, 암시적으로 글로벌 스코프에 같은 이름의 새로운 변수가 생성된다. 만약 'Strict Mode'인 경우라면 ReferenceError가 발생한다.


참고

  • You Don't Know JS - 타입과 문법, 스코프와 클로저( 한빛 미디어 )
728x90

'JAVASCRIPT' 카테고리의 다른 글

[JS][함수 vs 블록 스코프] 함수 기반 스코프  (0) 2022.02.16
[JS][렉시컬 스코프] 검색  (0) 2022.02.15
[JS][스코프] 스코프 이해하기  (0) 2022.02.15
[JS][스코프] 스코프란?  (0) 2022.02.15
[JS][문법] Switch  (0) 2022.02.14

댓글