개발 이야기/JavaScript

자바스크립트 동작 원리로 이해하는 호이스팅과 클로저

석구석구 2020. 3. 7. 00:24

실행문맥, Lexical Environment, OuterEnvironmentReference, EnvironmentRecord

자바스크립트의 동작 원리를 이해하면 자바스크립트의 특성들이 쉽게 이해가 됩니다.

 

이전에 콜 스택과 이벤트 큐, 이벤트 루프 이야기를 한 적이 있는데요, 오늘 다룰 이야기는 콜 스택에 쌓았던 그 친구에 대한 이야기입니다.

 

1. 실행 컨텍스트?

 

Execution context (abbreviated form — EC) is the abstract concept used by ECMA-262 specification for typification and differentiation of an executable code.


https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf

 

'실행 가능한 코드를 구분하고 정의하는 추상적 개념'

 

실행 컨텍스트를 쉽게 풀자면 '코드가 실행되는 환경'이라고 이해하시면 됩니다.

 

자바스크립트는 코드를 실행하기 위해서 코드가 실행되는 환경을 조성하게 되는데 이것이 실행 컨텍스트입니다.

 

어찌 보면 당연한 것이 코드를 실행하려면 우선 여러 가지 정보들을 알고 있어야 하기 때문입니다.

 

그렇다면 실행 가능한 코드는 무엇일까요.

 

  • Global code / 전역 코드

  • Function code / 함수 코드

  • eval 코드

위의 세 가지 코드들을 실행 가능한 코드이고 이를 구분 단위로 봅니다.

 

그러면 이러한 코드들(쉽게 생각해서 함수라고 생각합시다) 하나를 실행하기 위해 필요한 정보는 어떤 것이 있을까요?

 

  • 변수

  • 함수 선언

  • 스코프

  • this

이상과 같은 정보들이 될 겁니다.

 

자바스크립트 엔진은 이러한 환경들을 물리적 객체의 형태로 관리하고 이를 스택에 쌓아 관리합니다.

 

콜 스택에서 관리하던 데이터가 바로 이것이었던 거죠.

 

 

2. 실행 컨텍스트의 실체

 

실행컨텍스트는 3가지 프로퍼티를 가지고 있는 객체로 구현됩니다.

 

  1. Variable Object / 변수 객체

  2. Scope Chain / 스코프 체인

  3. thisValue / This로 참조할 컨텍스트 객체

 

하나씩 파고들어 봅시다.

 

1. Variable Object 

 

실행 컨텍스트가 생성되면 자바스크립트 엔진이 실행에 필요한 정보들을 담을 객체를 생성하게 되는데, 이를 활성 객체(변수 객체)라고 합니다.

 

활성 객체에는 변수와, 함수 선언, 매개변수와 인수들의 정보가 담기게 됩니다.

 

(전역 컨텍스트의 경우에는 매개변수와 인수 정보가 없겠죠)

 

var name = '이석규';

function outer(){
	var result = `my name is ${name}`;
	function inner(){
		console.log('함수가 실행 되었습니다.');
		console.log(hoist);
	}
    var hoist = 10;
	console.log(result);
    console.dir(inner);
    inner();
}

 

위와 같은 코드가 전역에서 실행된다면 활성 객체에는 name 변수와 outer 함수 선언이 활성 객체의 프로퍼티가 될 것입니다.

 

그리고 outer 함수가 실행되면 outer 실행 컨텍스트가 생성되고 이때의 활성 객체는 result 변수와 inner 함수 선언, 그리고 arguments를 가지게 될 것입니다.

 

2. Scope chain 

 

Scope chain는 일종의 리스트로서, 자신의 Variable object를 시작으로 중첩된 함수들의 Variable object들이 관리되고 있습니다. 그리고 마지막에는 Global Object가 있죠. 이 스코프 체인을 통해서 우리는 내부 함수에서 외부 중첩 함수들의 스코프에 접근할 수 있습니다.

 

3. This

실행 문맥의 This 값은 상황에 따라 다양하게 결정됩니다. 추후 this 값의 변화에 대해 포스팅할 예정입니다.

 

 

위의 코드를 그림으로 나타내면 아래와 같습니다.

 

 

실행컨텍스트 내의 활성 객체, 스코프 체인, 디스 객체

 

 

그림을 자세히 보시면 outer의 활성 객체가 생성될 때 내부의 hoist 변수가 undefined 값을 초기값으로 가지는 것을 알 수 있습니다.

 

이제 왜 호이스팅이라는 상황이 벌어지는지 정확하게 이해 할 수 있습니다.

 

호이스팅

 

실행 문맥이 생성되고 활성 객체가 생성되면서 내부 함수 선언의 함수명이 활성 객체의 프로퍼티로, 생성된 함수 객체가 값으로 할당된다.

 

실행 문맥이 생성되고 활성 객체가 생성 되면서 내부 변수 선언의 변수명이 활성 객체의 프로퍼티로, undefined가 값으로 할당된다.

 

클로저

콘솔에 찍힌 inner function의 [[Scopes]] 프로퍼티를 보면 스코프 체인을 확인할 수 있는데, 상위 문맥의 스코프가 클로저라는 이름으로 들어와 있음을 확인 할 수 있다.

 

내부 함수가 외부 함수의 맥락에 접근할 수 있다는 클로저의 정의가 정확하게 이해되는 순간이다.

 

보통 자바스크립트를 개발하면서 클로저라 함은 내부 함수를 리턴하면서 외부 함수의 실행이 끝났음에도 여전히 내부 함수에서 참조 가능한 상황을 일컫는다.

 

즉, 실행 컨텍스트의 관점에서 정리하자면, 외부함수의 실행이 끝났음에도 내부 함수에서 렉시컬 스코핑으로 인해 상위 컨텍스트 내의 활성 객체(변수 객체)를 스코프 체인으로 참조할 수 있는 상황이라 답할 수 있다.

 

 

참조 사이트

https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf

http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/#global-code

https://poiemaweb.com/

ECMA-262-3 in detail. Chapter 1. Execution Contexts.

Read this article in: Russian, Chinese, French.

dmitrysoshnikov.com

 

 

'개발 이야기 > JavaScript' 카테고리의 다른 글

@storybook/react  (0) 2020.06.02
ECMAScript2016 & ECMAScript2017 소개  (0) 2020.05.21
식과 문  (0) 2020.02.13
자바스크립트 V8 컴파일러의 동작.  (0) 2019.07.09
RxJS  (0) 2019.06.16