본문 바로가기
JAVASCRIPT

[JS][렉시컬 스코프] 검색

by KBS 2022. 2. 15.
728x90

렉시컬 스코프

'스코프'를 엔진이 확인자 이름으로 현재 스코프 또는 중첩 스코프 내에서 변수를 찾을 때 사용하는 '규칙의 집합'이라고 정의했다.

스코프는 두 가지 방식으로 작동한다. 첫 번재 방식은 다른 방식보다 훨씬 더 일반적이고 다수의 프로그래밍 언어가 사용하는 방식이다. 이 방식을 '렉시컬 스코프'라고 부른다. 두 번째 방식은 Bash Scripting이나 Perl의 일부 모드와 같음 몇몇 언어에서 사용하는 방식으로 '동적 스코프'라고 부른다.

렉스타임

일반적인 언어의 컴파일러는 첫 단꼐를 전통적으로 토크나이징 또는 렉싱이라 불리는 작업으로 시작한다. 렉싱 처리 과정에서는 소스코드 문자열을 분석하여 상태유지 파싱의 결과로 생성된 토큰에 의미를 부여한다. 바로 이 개념이 렉시컬 스코프가 무엇인지, 어원이 어디인지를 알게 해주는 바탕이 된다.

약간 순환적인 정의를 하면 렉시컬 스코프는 렉싱타임에 정의되는 스코프다. 바꿔말해 렉시컬 스코프는 개발자가 코드를 짤 때 변수와 스코프 블록을 어디서 작성하는가에 기초해서 렉서가 코드를 처리할 때 확정된다.

function foo(a) {
  var b = a * 2;
  function bar(c) {
    console.log(a, b, c);
  }

  bar(b * 3);
}

foo(2); /// 2, 4, 12

 

이 예제 코드에는 3개의 중첩 스코프가 있다. 스코프를 다음과 겹쳐진 버블이라고 가정하면 이해하기 쉽다.

  1. 버블1은 글로벌 스코프를 감싸고 잇고, 해당 스코프 안에는 오직 하나의 확인자만 있다.(foo)
  2. 버블2는 foo의 스코프를 감싸고 있고, 해당 스코프는 3개의 확인자(a, bar, b)를 포함한다.
  3. 버블3은 bar의 스코프를 감싸고 있고, 해당 스코프는 하나의 확인자(c)만을 포함한다.

스코프 버블은 스코프 블록이 쓰이는 곳에 따라 결정되는데, 스코프 블록은 서로 중첩될 수 있다. 일단 지금은 각가의 함수가 새로운 스코프 버블을 생성한다고 가정하자.

bar의 버블은 foo의 법르 내부에 완전히 포함된다. 바로 foo의 내부에서 bar 함수를 정의했기 때문이다.

버블은 서로의 경계가 교차할 수 있는 벤다이어그램이 아니다. 다시 말해, 어떤 함수의 버블도 동시에 다른 두 스코프 버블안에 존재할 수 없다. 어떤 함수도 두 개의 부모 함수안에존재할 수 없는 것처럼 말이다.

검색

엔진은 스코프 버블의 구조와 상대적 위치를 통해 어디를 검색해야 확인자를 찾을 수 있는지 안다.

앞의 코드를 보면 엔진은 console.log() 구문을 실행하고 3개의 참조된 변수 a, b, c를 검색한다. 검색은 가장 안쪽의스코프 버블인 bar() 함수의 스코프에서 시작한다. 여기서 a를 찾지 못하면 다음으로 가장 가까운 스코프 버블인 foo()의 스코프로 한 단계 올라가고, 이곳에서 a를 찾아 사용한다. 똑같은 방식이 b에도 적용된다. 단 c는 bar()내부에서 찾을 수 있다.

변수 c가 bar()foo() 내부에 모두 존재한다고 가정하면, console.log() 구문은 bar() 내부에 잇는 c를 찾아 사용하고 foo()에 있는 c는 찾으러 가지도 않는다.

스코프는 목표와 일치하는 대상을 찾는 즉시 검색을 중단한다. 여러 중첩 스코프 층에 걸쳐 같은 확인자 이름을 정의할 수 있따. 이를 '섀도잉'이라한다.(더 안쪽의 확인자가 더 바깥쪽의 확인자를 가리는 것) 섀도잉과 관계없이 스코프 검색은 항상 실행 지점에서 가장 안쪽 스코프에서 시작하여 최초 목표와 일치하는 대상을 찾으면 멈추고, 그전까지는 바깥/위로 올라가면서 수행한다.

글로벌 변수는 자동으로 웹 브로우저의 window 같은 글로벌 객체에 속한다. 따라서 글로벌 변수를 직접 렉시컬 이름으로 참조하는 것뿐만아니라 글로벌 객체의 속성을 참조해 간접적으로 참조할 수도 있다. window.a 가려져 있어서 다른 방식으로는 접근할 수 없는 글로벌 변수에는 이 방법을 통해 접근하 수 있다. 그러나 글로벌이 아닌 섀도 변수는 접근할 수 없다.

어던 함수가 어디서 또는 어덯게 호출되는 지에 상과넚이 함수의 렉시컬 스코프는 함수가 선언된 위치에 따라 정의된다.

렉시컬 스코프 검색 과정은 a, b, c와 같은 일차 확인자 검색에만 적요오딘다. 코드에서 foo.bar.baz의 참조를 찾는다고 하면 렉시컬 스코프 검색은 foo 확인자를 찾는데 사용되지만, 일단 foo를 찾고 나서는 객체 속성 접근 규칙을 통해서 bar와 baz의 속성을 각각 가져온다.


참고

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

댓글