[JavaScript] 렉시컬 환경 (Lexical Environment)

아지랑이·2024년 1월 28일
3

JavaScript

목록 보기
2/2
post-thumbnail

Lexical Environment 란?

렉시컬 환경(Lexical Environment)실행 컨텍스트(Execution Context)의 일부로서, 식별자(변수, 함수 등의 이름)와 그에 대응하는 값, 그리고 주변 스코프에 대한 정보를 관리하는 구조를 말합니다.

실행 컨텍스트(Execution Context) 구조

렉시컬 환경(Lexical Environment): 현재 실행 중인 코드 블록의 식별자 정보를 관리합니다. 즉, 현재 실행 컨텍스트에서 사용되는 변수와 함수를 담고 있으며, 이를 통해 스코프와 식별자의 조회 및 변경 등이 수행됩니다.

변수 환경(Variable Environment): 실행 컨텍스트가 생성되는 시점에 var 키워드로 선언된 변수와 함수 선언식에 대한 정보를 담습니다.






변수의 특징

varlet, const
Functional ScopeBlock Scope
No Temporal Dead ZoneTemporal Dead Zone

함수 스코프(Functional Scope) / 블록 스코프(Block Scope)

function LexicalEnvironment() {
    if (true) {
        let data = 1;    
    }
  
    console.log(data); // Uncaught ReferenceError: data is not defined
}

LexicalEnvironment();

function VariableEnvironment() {
    if (true) {
        var data = 1;    
    }
  
    console.log(data); // 1
}

VariableEnvironment();

comment.

var로 선언된 변수는 함수 스코프를 가집니다. 이는 해당 변수가 선언된 함수의 어떤 코드 블록 내에서든 접근이 가능하다는 것을 의미합니다. 즉, 함수 내부의 특정 코드 블록에서 var로 변수를 선언하더라도, 그 변수는 함수의 다른 부분에서도 접근 가능합니다. 이 변수들은 해당 함수의 환경 레코드에 저장됩니다.

반면 letconst로 선언된 변수는 블록 스코프를 가집니다. 이는 해당 변수가 선언된 코드 블록 내에서만 접근이 가능하다는 것을 의미합니다. 즉, let이나 const로 선언된 변수는 그 변수가 선언된 블록 내에서만 존재하며, 블록 밖에서는 그 변수에 접근할 수 없습니다.




스코프에 따른 환경 레코드 생성 과정

function BothEnvironment() {
	let LET_0 = 'out';
	var VAR_0 = 'out';
  
  	if (true) {
    	let LET_1 = 'in';
		var VAR_1 = 'in';
    }
}

comment.

이와 같이 var로 선언된 변수는 함수 스코프를 가지며, 선언된 함수의 환경 레코드에 저장됩니다.
반면, letconst로 선언된 변수는 블록 스코프를 가지게되며, 새로운 렉시컬 환경(Lexical Environment)을 생성하며, 이 환경 레코드에 저장됩니다.
이들은 선언된 코드 블록 내에서만 접근 가능하며, 해당 블록이 종료되면 변수는 더 이상 존재하지 않게 됩니다.




TDZ(Temporal Dead Zone)

comment.

Temporal Dead Zone(TDZ)letconst 키워드를 사용하여 변수를 선언한 뒤 그 변수를 초기화하기 전까지의 코드 영역을 의미합니다.
이 영역에서는 해당 변수를 참조하려고 하면 ReferenceError가 발생합니다.

자바스크립트에서 변수 선언은 세 단계로 이루어집니다: 선언 단계(Declaration phase), 초기화 단계(Initialization phase), 할당 단계(Assignment phase)입니다.

var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어지지만, letconst로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 있습니다.

let이나 const로 변수를 선언하면 그 변수는 선언 단계를 거친 후 TDZ에 들어갑니다. TDZ는 변수가 초기화되는 시점, 즉 변수 선언문에 도달할 때까지 유지됩니다. 이 영역에서 해당 변수를 참조하려고 하면 ReferenceError가 발생하는데, 이는 변수가 아직 초기화되지 않았기 때문입니다.

따라서, TDZletconst로 선언된 변수가 초기화되기 전까지의 코드 영역을 안전하게 보호하며, 변수를 선언하기 전에 참조하는 것을 방지합니다.

note.

이와 같이 var let const 변수는 종류마다 다른 방식으로 선언 과정을 거치게되며, 이는 추후 호이스팅(Hoisting)에 대한 포스트에서 자세히 서술하겠습니다.






렉시컬 환경(Lexical Environment) 구성요소

환경 레코드(Environment Record): 현재 스코프에 속한 모든 지역 변수를 저장하는 구조입니다. 함수 선언 및 변수 선언과 같은 선언적 환경 레코드와, this와 같은 객체 바인딩을 포함한 객체 환경 레코드가 있습니다.

외부 환경 참조(Outer Environment Reference): 현재 컨텍스트의 외부 스코프, 즉 부모 스코프를 참조합니다. 이를 통해 스코프 체인을 형성하며, 현재 컨텍스트에서 찾을 수 없는 식별자를 부모 스코프에서 찾을 수 있게 합니다.


환경 레코드(Environment Record)

전역 환경 레코드(Global Environment Record)
자바스크립트 코드가 실행되면 가장 먼저 생성되는 환경 레코드입니다. 이 환경 레코드는 코드의 전역 컨텍스트에서 사용되는 모든 전역 변수와 함수를 저장합니다. 이는 객체 환경 레코드를 생성하며, 이 객체 환경 레코드의 바인딩 오브젝트는 전역 객체를 참조합니다.

함수 환경 레코드(Function Environment Record)
함수가 호출될 때마다 새로운 환경 레코드가 생성됩니다. 이 환경 레코드는 해당 함수 내부에서 선언된 모든 변수와 함수를 저장합니다. 이 환경 레코드 내부에는 객체 환경 레코드와 선언적 환경 레코드가 생성될 수 있습니다. 이는 함수 내에서 어떤 유형의 식별자가 사용되었는지에 따라 결정됩니다.

선언적 환경 레코드(Declarative Environment Record)
이 환경 레코드는 let const 그리고 함수 선언 등의 식별자 정보를 저장합니다. 이는 블록 스코프를 가지므로, 해당 식별자가 선언된 블록 내에서만 접근이 가능합니다. 함수의 매개변수와 'catch'문의 예외 파라미터도 이 환경 레코드에 저장됩니다.

객체 환경 레코드(Object Environment Record)
객체 환경 레코드는 식별자를 특정 객체의 속성으로 취급합니다. 이 환경 레코드는 var로 선언된 변수와 함수 선언을 저장합니다. 이는 함수 스코프를 가지므로, 해당 식별자는 함수 내 어디서든 접근이 가능합니다.

모듈 환경 레코드(Module Environment Record)
이 환경 레코드는 ECMAScript 2015 (ES6)에서 도입된 모듈에 대한 정보를 저장합니다. 모듈 환경 레코드는 모듈 내에서 선언된 변수와 함수, 그리고 모듈로부터 내보낸 (exported) 식별자 등의 정보를 저장합니다.

var name = 'kimkyungsub';
let job = 'developer';

function foo() {
    var age = 25;
    const sex = 'male';

    function bar() {
        let country = 'south korea';
      	console.log(name,job,age,sex,country) // kimkyungsub developer 25 male south korea
    }
    bar();
}
foo();

comment.

var 변수는 컨텍스트 생성 단계에서 변수 환경(Variable Environment)undefined 상태로 초기화되며, 코드 실행 단계에서 var로 선언된 변수들에 값이 할당되면 이 값들은 렉시컬 환경(Lexical Environment)객체 환경 레코드(Object Environment Record)에 업데이트됩니다.




외부 환경 참조(Outer Environment Reference)

var name = 'kimkyungsub';
let job = 'developer';
const age = 25;

function foo() {
	const sex = 'man';

	function bar() {
    	const country = 'south korea';
      
      	function baz() {
        	console.log(name); // 'kimkyungsub'
        	console.log(job); // 'developer'
        	console.log(age); // 25
        	console.log(sex); // 'mane'
        	console.log(country); // 'south korea'
        }
      
    	baz();
    }
  
	bar();
}

foo();

comment.

이와 같이 모든 실행 컨텍스트에는 렉시컬 환경뿐만 아니라 외부 환경 참조(Outer Environment Reference)가 존재하며, 이는 외부 함수내에 내부 함수가 존재하는 경우 상위 스코프로 상위 함수를 참조하게 되며 이는 스코프 체인(Scope chain)이라고 합니다.
함수가 선언되어 변수를 호출하는 메소드를 사용하게 되면 가장 먼저 자신의 환경 레코드를 검색하며, 변수가 존재하지 않을 경우 차례대로 상위 스코프의 환경 레코드에서 변수를 검색하게 됩니다.
전역 실행 컨텍스트(Global Execution Context)는 외부 환경이 없기에 해당 컨텍스트까지 검색하여 필요한 변수가 없는 경우 ReferenceError가 발생됩니다.

0개의 댓글