일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 인텔리제이
- svn
- 봤어요처리
- REST
- oracle
- javascript error
- 코어자바스크립트
- 프로젝트 여러 개
- datagrip 한글깨짐
- maven
- Aspect
- class-transformer
- flutter mac 설치
- JavaScript
- MySQL
- 프로그래머스
- node.js
- ojdbc6
- InteliJ
- SQL
- DART
- Stream
- db
- TypeScript
- tecoble
- @RequestBody
- eqauls-hashcode
- Mac
- Spring
- Java
- Today
- Total
개발자가 되고 싶은 개발자
[JavaScript] 실행 컨텍스트 본문
(코어 자바스크립트(정재남 저- 위키북스)를 참조하여 작성했습니다.)
(ECMAScript Spec 9.4에 해당 내용이 명세되어 있습니다.)
실행 컨텍스트(Excecution Context)
실행 컨텍스트는 실행할 코드에 제공할 환경 정보를 모아놓은 객체입니다.
자바스크립트 엔진이 코드를 실행하기 위해 알아야 할 정보들이 모여있습니다.
즉, 실행 가능한 자바 스크립트 코드가 실행되기 위해 필요한 환경이라 이해할 수 있습니다.
해당 개념을 공부하면서 자바스크립트는 동적 언어라는 성격을 잘 파악할 수 있습니다.
자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 호이스팅(선언된 변수를 위로 끌어올림), 외부 환경 정보 구성, this값 설정 등의 동작을 수행합니다.
자바스크립트 코드가 동작하는 원리를 이해하기 위해 해당 개념을 잘 파악해야 합니다.
이러한 동작을 유의하며 실행 컨텍스트를 살펴보겠습니다.
실행 컨텍스트 구성
동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고, 이를 콜 스택에 쌓아올렸다가 top의 컨텍스트와 관련있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장합니다.
동일한 환경에는 전역공간, eval() 함수, 함수 등이 있습니다.
흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것입니다.
책의 2-1번 예제입니다.
해당 자바스크립트 코드가 실행되자마자 콜 스택에 어떤 순서로 실행 컨텍스트가 쌓이는지 알아보겠습니다.
// ------------------------------(1)
var a = 1;
function outer() {
function inner() {
console.log(a); //undefined
var a = 3;
}
inner(); //------------------(2)
console.log(a); //1
}
outer(); //-----------------------(3)
console.log(a); //1
- 전역 컨텍스트
- outer
- inner
위의 순서대로 쌓이게 되고, 스택 구조 이므로 실행은 역순이 됩니다.
전역 공간을 둘러싸는 외부 스코프는 존재할 수 없습니다.
자바스크립트 파일이 열리는 순간 전역 컨텍스트는 활성화 됩니다.
어떤 실행 컨텍스트가 활성화 될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장합니다.
(엔진이 활용하기 위해 생성되는 정보로서, 개발자가 코드로 확인할 순 없습니다.)
실행 컨텍스트 객체에 저장되는 정보들은 다음과 같습니다.
- VariableEnviroment: (선언 시점) LexicalEnvironment의 스냅샷입니다. -> 선언 시점이므로 변경 사항은 반영되지 않습니다.
현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보를 갖습니다. - LexicalEnvironment: 처음엔 VariableEnviroment와 같지만, 변경 사항이 실시간으로 반영됩니다.
- ThisBinding: this 식별자가 바라봐야 할 대상 객체입니다.
VariableEnviroment
내부는 enviromentRecord와 outer-EnvironmentReference로 구성돼 있습니다.
LexicalEnvironment와 내부가 동일합니다.
초기화 과정은 둘 다 동일합니다.
LexicalEnvironment
형용사 1. 어휘의. 2. 사전(辭典)의.
'어휘적 환경', '정적 환경'이라는 단어로 가장 많이 등장한다고 합니다.
하지만 수시로 변하는 환경 정보의 의미하는 번역으로 '정적 환경은' 적절하지 않고, 어휘적은 사전을 단순 치환한 것이기 때문에 저자는 '사전적인' 이라는 표현으로 설명합니다.
그래서, LexicalEnvironment를 '사전적 환경' 으로 받아드리며 글을 이어나가도록 하겠습니다.
책에서 예시를 든것 처럼,
"현재 컨텍스트의 내부에 ~~와 같은 식별자들과 그 외부 정보는 ~를 참조하도록 구성돼있습니다."와 같이 컨텍스틀를 구성하는 환경 정보들을 모아놓은 것으로 받아드리면 됩니다.
enviromentRecord
현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장됩니다.
컨텍스트를 구성하는 함수에 지정된 매개변수 이름, 선언된 함수 그 자체, var로 선언된 변수의 식별자 등이 식별자 정보에 해당됩니다.
컨텍스트 내부 전체를 A to Z 순서대로 수집합니다.
수집 -> 실행
즉, 코드가 실행되기 전 엔진이 이미 해당 환경에 속한 코드의 변수명들을 모두 알고 있습니다.
변수 정보를 수집하는 과정을 이해하기 편하도록 호이스팅이라는 가상의 개념이 등장합니다.
hoist(끌어올리다) + ing = hoisting(끌어 올리는 과정)
실제 자바스크립트 엔진이 끌어올리는 작업을 진행하지는 않지만, 편의상 그렇게 간주하는 것입니다.
function a(x) {
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);
호이스팅의 개념을 모른다면 1, undefined, 2와 같은 결과를 예상할 수 있지만 실제 출력은 1,1,2가 출력됩니다.
호이스팅 처리된 결과는 다음과 같을 것입니다.
function a() {
var x;
var x;
var x;
x = 1;
console.log(x);
console.log(x);
x = 2;
console.log(x);
}
a(1);
매개변수, var로 선언된 식별자 등이 enviromentRecord에 저장된다고 했습니다.
실제로는 호이스팅 되었을 때 동일한 변수들이 선언되었으므로 무시되어 x는 한 번만 선언되는 것과 마찬가지로 동작합니다 .
function a() {
console.log(b);
var b = 'bbb';
console.log(b);
function b() {};
console.log(b);
}
a();
- var로 선언된 식별자와 함수 자체가 호이스팅됩니다.
- 변수의 할당부는 원래 있던 자리에 남지만, 함수는 전체가 끌여올려집니다.
- 그래서 b를 선언하고, b에 함수를 할당하는 꼴이 됩니다.
- 첫 번째 로그에는 [Function: b]가 출력됩니다.
- 할당하는 로직은 그 자리에 그대로 있기 때문에 함수가 'bbb'로 재할당됩니다.
- 그 후의 로그는 둘 다 bbb가 출력됩니다.
스코프, 스코프 체인, outerEnvironmentReference
스코프는 식별자에 대한 유효범위를 의미합니다.
해당 식별자를 어디에서까지 접근할 수 있는지를 의미합니다.
ES5까지는 전역공간을 제외하고 오직 함수에 의해서만 스코프가 생성됩니다.
어디서 접근할 수 있는지 안에서부터 바깥까지 차례로 검색하는 것이 바로 스코프 체인입니다.
LexicalEnvironment의 두 번째 수집자료인 outerEnvironmentReference가 이 스코프 체인을 가능하게 합니다.
outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조합니다.
선언될 시점에서의 LexicalEnvironment만 참조하므로, 가장 가까운 요소부터 차례로 접근가능합니다.
여러 스코프의 동일한 식별자를 선언한 경우, 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근이 가능하게 됩니다.
+ 함수 선언문 & 함수 표현식
함수 선언문은 함수를 선언하고 별도의 할당문이 없는 것을 말합니다.
- 반드시 함수명이 정의돼 있어야 합니다.
함수 표현식은 정의한 function을 별도의 변수에 할당하는 것을 말합니다.
- 함수명이 정의돼 있지 않아도 됩니다.
- 함수명을 정의하지 않은 표현식을 '익명 함수 표현식'이라고 합니다.
- 일반적으로 함수 표현식은 익명 함수 표현식을 말합니다.
function a () {} // 함수 선언문. a가 곧 변수명.
var b = function() {} // 함수 표현식(익명). b가 곧 함수명.
var c = function d() {} // 함수 표현식(기명). 변수명은 c, 함수명은 d
a(); //ok
b(); //ok
c(); //ok
d(); //error
호이스팅으로 인해 생길 수 있는 문제때문에 상대적으로 함수 표현식이 안전합니다.
'Dev > JavaScript & TypeScript' 카테고리의 다른 글
[TypeScript] 이펙티브 타입스크립트-(Part.2) 2장 타입스크립트의 타입 시스템 (0) | 2022.05.03 |
---|---|
[JavaScript] this (0) | 2022.05.03 |
[TypeScript] 이펙티브 타입스크립트-(Part.1) 2장 타입스크립트의 타입 시스템 (0) | 2022.04.25 |
[TypeScript] 이펙티브 타입스크립트- 1장 타입스크립트 알아보기 (0) | 2022.04.18 |
[JavaScript] 데이터 타입- 참조형 (0) | 2022.04.18 |