프로그래밍 언어/Javascript

[Javascript] Javascript 동작(1)

hanrabong 2022. 3. 20. 20:01

JS(ko.wikipedia.org)

Javascript란?

Javascript는 싱글 쓰레드로 동작하는 객체 기반의 스크립트 언어입니다. 웹 브라우저나 Node와 같은 런타임 환경에서 실행이 됩니다.

Javascript에는 hoisting, call by sharing, prototype, closure 등 다른 프로그래밍 언어에서 찾아볼 수 없는 특징들이 있습니다. 또한 런타임 환경에서는 비동기 작업을 하기도 합니다.

 

 

Javascript는 어떻게 동작할까? 

 Javascript가 어떻게 동작하는지 알기 위해서 먼저 Execution context와 Execution Stack에 대해서 알아야 합니다. Execution context와 stack에 대해서 잘 알면 나중에 hoistong이나 closure와 같은 개념에 대해서 더 잘 이해할 수 있습니다.

 

Execution Context란?

 Execution Context는 Javascript가 실행되는 추상적인 공간이라고 생각하면 됩니다. Javascript code는 항상 execution context 안에서 실행된다고 알면 됩니다.

 Execution Context에는 3가지 타입이 있습니다. 각 타입을 간략하게 보겠습니다.

 

  • Global Execution Context: 가장 기본적인 execution context로 프로그램에 하나의 global execution context만 존재해야 합니다. 함수 안에서 실행되지 않는 code들이 전부 global execution context에서 실행된다고 보면 됩니다. 2가지 일을 수행하는데 첫 번째로는 global object를 생성하고 두 번째로 this 값을 global object로 설정합니다.

 

  • Functional Execution Context: 함수가 호출될 때마다 새로운 execution context가 생성됩니다. global execution context와는 다르게 각 함수는 자기만의 execution context를 가지고 있습니다. 함수를 호출할 때 execution context가 생성이 되는데 정의된 순서대로 일련의 단계를 거칩니다.

 

  • Eval Function Execution Context: eval function안에서 실행되는 코드또한 자신만의 execution context를 갖고 있습니다. 하지만 eval은 주로 개발자가 다룰일이 없기에 다루지 않겠습니다.

 

Execution Stack이란?

 Execution context에 대해서 위해서 얘기를 해봤습니다. 그럼 Execution Stack은 무엇일까요? Stack이라는 것에서 유추를 할 수 있습니다. Execution Stack은 call stack이라고도 하며 stack 자료구조처럼 LIFO(Last in First out) 특징이 있습니다. 코드가 실행될 때 모든 execution context를 execution stack에 저장하여 실행시킵니다. 

 

자바스크립트 엔진이 처음에 코드를 마주치면 global execution context를 만들어서 execution stack에다가 push합니다. 그 후에 engine이 함수를 마주치면 해당 함수에 대한 새로운 execution context를 생성해서 stack에 push합니다. 그리고 engine이 stack top에 있는 function을 실행시키고 실행이 끝나면 stack에서 pop시킵니다. 

 

예를 들어서 설명해 보겠습니다.

 

console.log('global execution context');

function hello() {
	console.log('hello');
	world();
}

function world() {
	console.log('world');
}

hello();

 

Execution Context Stack

 

 위와 같은 code가 실행이 되면 javascript engine은 global execution context을 만들어서 execution stack에 push합니다. 그 후에 hello() 함수를 마주치면 해당 함수에 대한 execution context를 만들어서 stack에 push합니다. hello 함수 내부에서 world()를 마주치면 world 함수에 대한 execution context를 만들어서 stack에 push합니다. world()함수 실행이 끝나면 stack에서 pop되고 hello()도 실행이 끝나면 pop() 됩니다. 그 후에 모든 코드가 실행이 끝나면 global execution context도 stack에서 제거됩니다.

 

 

 

Exection Context가 어떻게 생성되고 실행이 될까요?

 위에서 js engine이 execution context를 생성하고 context가 execution stack에 push되었다가 pop된 것을 보았습니다. 이제 execution context가 js engine에 의해서 어떻게 생성이 되는 지를 알아보겠습니다.

 

Execution context는 각 단계에 의해 생성이 되고 실행이 됩니다.

1) Creation Phase(생성 단계)

2) Execution Phase(실행 단계)

 

각 단계를 살펴보겠습니다.

 

 

Creation Phase

 Execution context는 생성 단계에 생성이 됩니다. 생성 단계에서 다음과 같은 component기 생성이 됩니다.

 

  • LexicalEnvironment
  • VariableEnvironment

Execution context
Lexical Environment & Variable Environment

 

Lexical Environment

 

 공식 ES6 문서를 보면 Lexical environment에 대해서 다음과 같이 설명합니다.

A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code. A Lexical Environment consists of an Environment Record and a possibly null reference to an outer Lexical Environment.

 간단히 말하면 lexical environment는 identifier-variable mapping을 보유하는 구조입니다. identifier는 함수 나 변수의 이름이라고 생각하면 되고 variable은 실제 객체(function object, array object 포함) 나 primitive value에 대한 참조입니다.

LexicalEnvironment = {
  Identifier:  <value>,
  Identifier:  <function object>
}

 

예를 들어서 설명을 해보겠습니다. 

 

let a = 10;
let b = 10;

function hello(){
	console.log('hello');
}

 

위와 같은 코드가 존재할 때 아래와 비슷하게 lexical environment에 저장이 됩니다.

LexicalEnvironment = {
	a: 10,
	b: 20,
	hello: <ref. to hello function>
}

 

 

각 Lexical Environment에는 2개의 component가 있습니다. 위의 공식 ES6문서에서 Lexical environment를 설명한 인용을 보면 다음과 같이 구성 component가 있습니다.

A Lexical Environment consists of an Environment Record and a possibly null reference to an outer Lexical Environment. 
  • Environment Record
  • Reference to the outer environment

각 component에 대해서 이야기 해보겠습니다.

 

Environment Record

 environment record는 변수 및 함수 선언이 lexical environment 내부에 저장되는 장소입니다. 

 

environment record에는 2가지 유형이 있습니다.

 

  • Declarative environment record

 

  • Object environment record

 

Declarative environment record

 

 ES6 공식 문서에 다음과 같이 정의하고 있습니다.

Each declarative Environment Record is associated with an ECMAScript program scope containing variable, constant, let, class, module, import, and/or function declarations. A declarative Environment Record binds the set of identifiers defined by the declarations contained within its scope.

 쉽게 말하면 declarative environment record는 범위 내에 포함된 선언에 의해 정의된 identifiers를 binding 합니다. variable, constant, let, class, 함수 선언등을 포함합니다. 

 

 

Object environment record

 

 ES6 공식 문서에 다음과 같이 정의하고 있습니다.

Object Environment Records are used to define the effect of ECMAScript elements such as WithStatement that associate identifier bindings with the properties of some object.

 object environment records는 일부 개체의 속성과 연결하는 WithStatement와 같은 효과를 정의하는 데 사용됩니다.

 

Reference to the outer environment

 Refernece to the outer environment는 말 그대로 외부 환경에 대한 참조입니다. 외부 lexical environment에 접근을 할 수 있다는 말이기도 합니다. Js engine이 현재 lexical environment에서 변수를 찾지 못하면 outer lexical environment 내에서 변수를 찾습니다.

 

다음과 같은 코드를 예시로 들어보겠습니다.

 

let a = 10;

function sum(b) {
  return a + b;
}

sum(20);  // result 30

 위에서 js engine은 처음에 global execution context를 생성하여 execution stack에 push합니다. 그 후에 sum(20)함수를 만나면 해당 execution context를 만들어서 push합니다. 나중에 이야기를 할 내용이지만 execution phase에서 변수를 할당하고 코드를 실행하는데 sum function execution context에서 a라는 변수를 참조하지 못하기에 해당 execution context 외부에서 변수 a의 값을 참조하여 10이라는 값을 얻을 수 있습니다.

 

 

Variable Environment

 Variable environment 또한 execution context내에서 변수선언을 통해 생성된 변수들을 저장합니다. 위에서 설명한 lexical environment의 구성요소를 똑같이 갖고 있습니다.

 

lexical environment와의 차이점을 보면, ES 6 공식문서에서 다음과 같이 나와있습니다.

 

Identifies the Lexical Environment whose EnvironmentRecord holds bindings created by VariableStatements within this execution context.

A var statement declares variables that are scoped to the running execution context’s VariableEnvironment.

 위의 내용으로 인해 var로 선언한 변수는 lexical environment가 아니라 variable environment에 저장이 된다는 것을 알 수 있습니다.

 

 

 

글이 좀 많이 길어져서 Execution Phase에 대한 내용은 다음 글에서 설명하겠습니다.

 

 

 

※ 해당 글은 밑에 blog를 번역하며 ES6문서를 보고 내용들을 추가하였습니다. 틀린 점이나 궁금한 점이 있으면 댓글 달아주세요

 

 

참고자료

https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0

 

Understanding Execution Context and Execution Stack in Javascript

Understanding execution context and stack to become a better Javascript developer.

blog.bitsrc.io

https://262.ecma-international.org/6.0/

 

ECMAScript 2015 Language Specification – ECMA-262 6th Edition

5.1.1 Context-Free Grammars A context-free grammar consists of a number of productions. Each production has an abstract symbol called a nonterminal as its left-hand side, and a sequence of zero or more nonterminal and terminal symbols as its right-hand sid

262.ecma-international.org

 

 

 

'프로그래밍 언어 > Javascript' 카테고리의 다른 글

[Javascript] Data type - Primitive type  (0) 2022.04.26
[Javascript] Closure란?  (0) 2022.04.23
[JavaScript] Hoisting이란?  (0) 2022.04.19
[Javascript] Javscript 동작(2)  (0) 2022.04.05