Core JavaScript #2

milkboy2564·2022년 12월 14일
0

실행 컨텍스트란?

  • 실행 컨텍스트는 실행할 코드에 제공할 환경 정보를 모아놓은 객체다.
  • 우리가 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것 뿐이다.
  • 콜 스택에 실행 컨텍스트들이 쌓이는 것은 코드를 평가하는 과정에서 이루어진다.(위에서 아래로 동기적으로 실행)

실행 컨텍스트 객체가 가지는 환경 정보

VariableEnviroment

현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보, 선언 시점의 LexicalEnvironment의 스냅샷으로, 변경 사항은 반영되지 않음.

LexicalEnvironment

처음에는 VariableEnvironment와 같지만 변경 사항이 실시간으로 반영

ThisBinding

this 식별자가 바라봐야 할 대상 객체

VariableEnvironment

LexicalEnvironment와 같은 내용이지만 최초 실행 시의 스냅샷을 유지한다는 점이 다르다.
실행 컨텍스트를 생성할 때 VariableEnvironment를 생성하고 이를 복사해 LexicalEnvironment를 만들어 사용한다.

LexicalEnvironment

LexicalEnvironment의 내부에는 environmentRecordouterEnvironmentReference로 구성돼 있다.

environmentRecord에는 현재 컨텍스트와 관련된 코드의 식별자 정보가 저장된다.
식별자는 함수 매개변수 식별자, 함수 자체, var로 선언된 변수의 식별자 등이 있고 위에서부터 아래로 탐색하면서 순서대로 수집한다.

이렇게 변수 수집 과정을 모두 마친 상태는 코드가 아직 실행되기 이전 상태다. 하지만 코드가 실행되기 이전에 자바스크립트 엔진은 이미 식별자들의 정보들을 가지고 있게 된다. 그리고 바로 여기서 발생하는게 호이스팅(Hoisting)이다.

Hoisting

호이스팅이란 변수나 함수의 선언부가 코드를 실행하기 전(함수 평가 과정)에서 자바스크립트 엔진에 의해 최상단으로 끌어올려지는 현상을 말한다.

자바스크립트 내의 모든 선언(Ex.let, const, var, 함수, class 등)는 Hoisting이 발생한다. let, const, class 등은 호이스팅이 일어나지만 코드 실행 과정에서 값이 할당되기 이전에 값을 읽으려고 하면 참조 에러가 발생하는데 이는 스코프의 시작부터 변수의 선언까지 일시적 사각 지대(Temporal Dead Zone, TDZ)에 빠지기 때문이다.

함수 선언문과 함수 표현식

함수를 선언하는 방식은 함수 선언문과 함수 표현식이 존재한다.

함수 선언문은 function 정의부만 존재하고 별도의 할당 명령이 없는 것을 의미하고 함수 표현식은 정의한 function을 별도의 변수에 할당하는 것을 말한다.

함수 선언문은 반드시 함수의 이름이 정의돼 있어야 하는 반면, 함수 표현식은 함수 이름이 없이 작성해도 된다.
그래서 함수 선언문을 '기명 함수 표현식', 함수 표현식은 '익명 함수 표현식'이라고 부르기도 한다.

또한 함수 선언문은 함수 전체를 호이스팅 하는 반면 함수 표현식은 변수 선언부만 호이스팅하게 된다. 자바스크립트에서 함수는 일급 객체로 취급되고 이러한 특성으로 인해 하나의 값으로 취급될 수 있다는 것이 바로 이런 점이다.

❗️ 일급 객체
일급 객체란 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다. 자바스크립트에서 함수는 일급 객체로 평가된다.

일급 객체의 조건의 아래와 같다.

  • 변수에 할당(assignment)할 수 있다.
  • 다른 함수를 인자(argument)로 전달 받는다.
  • 다른 함수의 결과로서 리턴될 수 있다.

함수가 일급 객체이기에 가능한 것은 아래와 같다.

  • 고차함수(Higher order function)를 만들 수 있다.
  • 콜백(callback)을 사용할 수 있다.
// 호이스팅이 일어나기 전
console.log(sum(1, 2));
console.log(multiply(3, 4));

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

var mutiply = function(a, b) {
 	return a * b; 
}
// 호이스팅이 일어난 후
var sum = function sum(a, b) {
	return a + b;
}

var mutiply;

console.log(sum(1, 2));
console.log(multiply(3, 4));

multiply = function (a, b) {
 	return a * b; 
}

스코프 체인

스코프란 식별자에 대한 유효 범위를 의미한다.

다른 언어와 달리 자바스크립트는 오직 함수에 의해서만 스코프가 생성된다. 이렇게 생성된 스코프(생성자의 유효 범위)를 안에서부터 바깥으로 차례로 탐색하는 것을 스코프 체인이라고 한다.
그리고 이를 가능하게 만들어 주는 것이 LexicalEnvironment의 두 번째 수집 자료인 outerEnvironmentReference이다.

현재 콜스택 최상단에 위치한 실행 컨텍스트가 활성화 될 때 LexicalEnvironmentouterEnvironmentReference를 통해 점차 상위의 LexicalEnvironment를 탐색하는 것이 스코프 체인이다. 이렇게 계속해서 상위 컨텍스트를 탐색하다보면 결국 전역 컨텍스트까지 올라가게 될 것이다.

만약 어떠한 식별자가 전역 컨텍스트에도 존재하고 현재의 컨텍스트에도 존재한다면 무조건 스코프 체인 상에서 먼저 발견된 식별자에만 접근이 가능하다.
이런 식으로 동일한 변수의 이름을 스코프 체인 상의 가까운 스코프에 선언하여 해당 변수에 접근할 수 없게 만드는 것이 변수 은닉화라고 한다.

정리

  • 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체다. 실행 컨텍스트는 전역 공간에서 자동으로 생성되는 전역 컨텍스트와 eval 및 함수 실행에 의한 컨텍스트 등이 있다. 실행 컨텍스트 객체는 활성화 되는 시점에 VariableEnvironment , LexicalEnvironment, ThisBinding의 세 가지 정보를 수집한다.
  • 실행 컨텍스트를 생성할 때는 VariableEnvironment 와 LexicalEnvironment 가 동일한 내용으로 구성되지만 LexicalEnvironment 는 함수 실행 도중에 변경되는 사항이 즉시 반영되는 반면 VariableEnvironment 는 초기 상태를 유지한다.
  • VariableEnvironment 와 LexicalEnvironment 는 매개변수명, 변수의 식별자, 선언한 함수의 함수명 등을 수집하는 environmentRecord 와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference 로 구성돼 있다.
  • 호이스팅은 코드 해석을 좀 더 수월하게 하기 위해 environmentRecord 의 수집과정을 추상화한 개념으로, 실행 컨텍스트가 관여하는 코드 집단의 최상단으로 이들을 '끌어올린다'고 해석하는 것이다. 변수 선언과 값 할당이 동시에 이뤄진 문장은 '선언부'만을 호이스팅하고, 할당 과정은 원래 자리에 남아있게 되는데, 여기서 함수 선언문과 함수 표현식의 차이가 발생한다.
  • 스코프는 변수의 유효범위를 말한다. outerEnvironmentReference 는 해당 함수가 선언된 위치의 LexicalEnvironment 를 참조한다. 코드 상에서 어떤 변수에 접근하려고 하면 현재 컨텍스트의 LexicalEnvironment 를 탐색해서 발견되고 그 값을 반횐하고, 발견하지 못한 경우 다시 outerEnvironmentReference 에 담긴(참조하는) LexicalEnvironment를 탐색하는 과정을 거친다. 전역 컨텍스트의 LexicalEnvironment까지 탐색해도 해당 변수를 찾지 못하면 undefined 를 반환한다.
  • 전역 컨텍스트의 LexicalEnvironment 에 담긴 변수를 전역변수라고 하고, 그 밖의 함수에 의해 생성된 실행 컨텍스트의 변수들을 모두 지역변수라고 한다. 안전한 코드 구성을 위해 가급적 전역변수의 사용은 최소화 하는 것이 좋다.
  • this 에는 실행 컨텍스트를 활성화하는 당시에 지정된 this 가 저장된다. 함수를 호출하는 방법에 따라 그 값이 달라지는데, 지정되지 않은 경우에는 전역 객체가 저장된다
profile
FE 개발자

0개의 댓글