렉시컬 스코프(Lexical Scope)와 렉시컬 환경(Lexical Environment)

이동준·2023년 7월 24일
0

자바스크립트

목록 보기
13/28

렉시컬 스코프(Lexical Scope)

렉시컬 스코프(Lexical Scope) === 정적 스코프(Static Scope)
같은 말이다.

렉시컬 스코프는 함수를 어디에 선언하였는지에 따라 상위 스코프가 결정되는 것을 말한다.
자바스크립트를 포함한 대부분의 프로그래밍 언어는 렉시컬 스코프를 따르며, 정적 스코프(static scope)라고 부르기도 한다.

let x = 1;

function foo() {
	let x = 10;
	bar();
}

function bar() {
	console.log(x);
}

foo(); // 1
bar(); // 1

위와 같은 상황에서 bar() 함수에서 참조하는 x 변수는 bar() 함수의 상위 스코프가 무엇인지에 따라 결정된다. 상위 스코프가 무엇인지 알려면 함수가 선언된 위치를 봐야한다.
위 코드에서 bar() 함수는 전역에 선언되었으므로 상위 스코프는 전역 스코프가 된다.
그래서 bar() 함수 내에 x 변수는 전역에 선언된 x 변수를 참조하게 된다.

렉시컬 환경(Lexical Environment)

특정 코드가 작성, 선언된 환경(위치)을 의미한다. 코드 block , function , script 를 실행하기 앞서 생성되는 특별한 객체로, 실행할 스코프 범위 안에 있는 변수와 함수를 프로퍼티로 저장하는 객체이다.

렉시컬 환경에는 총 두가지, 글로벌 렉시컬 환경외부 렉시컬 환경이 있다.

글로벌 렉시컬 환경

전역 코드가 실행되면 글로벌 렉시컬 환경 객체가 만들어지고, 코드를 실행하기 전에 선언되어 있는 변수와 함수를 먼저 글로벌 환경 레코드에 저장한다.

변수 선언 방식에 따른 차이

var 로 선언된 변수는 환경 레코드에 변수 이름을 key 로, undefinedvalue 로 하여 초기화된다.
그러나 let , const 로 선언된 변수의 경우 환경 레코드에 변수 이름을 key 로, <uninitialized> 라는 상태를 value 로 초기화한다.
그래서 이 변수가 선언된 줄에 도달하기 전에 변수를 참조하고자 한다면, var 와 달리 ReferenceError 라 발생한다. 이 개념을 이해하면 호이스팅에 대해 좀 더 자세히 이해할 수 있다.

함수가 선언식으로 선언된 경우 var 로 선언된 변수와 달리 함수 선언식은 함수 이름을 key 로 하고 함수 자체를 value 로 저장하여 완전하게 초기화된다.
var 로 선언된 변수는 선언 줄 전에 접근하면 초기화 값인 undefined 를 리턴하는 반면, 함수 선언식은 초기화 될 때 완전하게 저장되므로 선언 줄 이전에 접근하더라도 의도대로 해당 함수를 사용 할 수 있다.

외부 렉시컬 환경

코드를 실행할 때 필요한 변수를 해당 로컬 스코프와 연관되어 있는 환경 레코드에서 먼저 찾은 후, 찾지 못했다면 렉시컬 환경이 갖고 있는 외부 렉시컬 환경에 대한 참조로 접근하여 찾는다. 이 과정을 반복하며 글로벌까지 도달하여 식별자를 검색하고, 없다면 에러가 발생하는 것이다. ("use strict" 엄격 모드일 경우에만)

function makeCount() {
  let count = 0;
  
  return function() {
    return count ++;
  };
}

let counter = makeCount();

makeCount() 함수가 호출을 시작할 때, 새로운 렉시컬 환경이 만들어진다. 그 안에 count 라는 로컬 변수가 저장된 후, return 문 뒤에 함수까지 counter 변수에 저장된다.
counter 를 실행 시키면 makeCount() 에 안에 있던 count 변수를 참조하여 0이라는 값이 리턴된다. 여기서 클로저의 대한 개념이 나오게 된다.

모든 함수는 [[Environment]] 라는 내부 프로퍼티를 가지고 있다. 이 프로퍼티는 함수가 만들어질 때 그 함수를 둘러싼 외부 렉시컬 환경에 대한 참조를 저장한다.
makeCounter 가 실행되면서 counter 함수는 만들어지고 이 때 makeCounter 의 렉시컬 환경에 대한 참조가 counter.[[Environment]] 프로퍼티에 저장된다. 그리고 counter 함수가 실행 될 때, 비로소 counter 함수의 렉시컬 환경 객체가 생성되고, 이 객체가 외부 렉시컬 환경에 대한 참조를 counter.[[Environment]] 프로퍼티로부터 가져온다. 이러한 과정으로 인해 counter 함수가 언제든 어디서 실행되든 count 변수를 참조 할 수 있게 되는 것이다.

0개의 댓글