[코어 자바스크립트] 02 실행 컨텍스트

임승민·2022년 12월 10일
0
post-thumbnail

01 실행 컨텍스트란?

앞서 알아야할 스택

스택: 후입 선출(저장량 넘치면 에러 발생) : 선입 선출

실행 컨텍스트: 실행할 코드에 제공할 환경 정보들을 모아놓은 객체

같은 환경의 코드 실행 시 필요한 환경 정보를 모아 컨텍스트를 구성한다.
그 후 콜스택에 쌓고 맨 위의 컨텍스트와 관련된 코드 실행해 전체 코드의 환경, 순서를 보장한다.

실행 컨텍스트 구성 방법

  • 전역공간 (자동 생성)
  • eval함수 (위험⚠️)
  • 함수 (best 👍)
  • block 생성 (ES6)
    전역공간, eval함수를 제외한다면 함수를 실행해 컨텍스트를 구성할 수 밖에 없다.

⚠️eval함수는 문자열 스크립트 코드를 실행하는 함수이다. 하지만 보안위험이 있어 사용해선 안된다.⚠️

console.log('2 + 2'); //'2 + 2'
console.log(eval('2 + 2')); //4

실행 컨텍스트 과정

var a = 1; // 전역 컨텍스트
function outer () { // outer 컨텍스트
  function inner () { // inner 컨텍스트
    console.log(a); // undefined
    var a = 3;
    console.log(a); // 3
  }
  inner();
  console.log(a); // 1
}
outer();
console.log(a); // 1
  1. JS코드 실행 시 전역 컨텍스트가 콜스택에 담긴다.
    최상단 공간은 브라우저에서 자동으로 실행한다. (JS파일 열리면 전역 컨텍스트 활성화)
  2. outer함수 호출, 콜스택 맨위로 전역 컨텍스트 관련 코드 실행 중단 후 내부 코드 실행
  3. inner함수 호출, 콜스택 맨위로 outer 컨텍스트 관련 코드 실행 중단 후 내부 코드 실행
  4. inner함수 실행 후 종료, inner 실행 컨텍스트 콜스택에서 제거
  5. outer함수 마저 실행 후 종료, outer 실행 컨텍스트 콜스택에서 제거
  6. 전역 공간 코드 마저 실행, 전역 컨텍스트 콜스택에서 제거(콜스택 빔 = 종료)

실행 컨텍스트 구성

아래는 실행 컨텍스트 구성 시 실행 컨텍스트 객체에 저장되는 정보들이다. (js엔진이 활용할 목적)

  • VariableEnvironment : 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보.
    선언 시점의 LexicalEnvironment의 스냅샷으로, 변경사항은 반영되지 않음.
  • LexicalEnvironment : 처음에는 VariableEnvironment와 같지만 변경사항이 실시간으로 반영됨.
  • ThisBinding : this 식별자가 바라봐야 할 대상 객체.

02 VariableEnvironment

실행 컨텍스트 생성 시 VariableEnvironment에 정보 담고, 복사해 LexicalEnvironment를 만든다.
이후엔 LexicalEnvironment를 주로 활용한다.

03 LexicalEnvironment

LexicalEnvironment는 2가지 정보를 수집한다.
environmentRecordouterEnvironmentReference이다.

2-3-1 environmentRecord와 호이스팅

environmentRecord에는 현 컨텍스트와 관련된 식별자 정보가 저장된다.

  • 컨텍스트를 구성하는 함수의 매개변수 식별자
  • 선언한 함수의 함수자체
  • var로 선언된변수의 식별자 등

호이스팅: JS엔진은 식별자들을 최상단으로 올려놓고 실제 코드를 실행한다.
(변수 정보 수집 과정 이해를 위한 가상 개념, 실제 동작 방식X)

⚠️ JS엔진 구동 방식을 이해하기 위해 코드를 변경했다. 실제론 이러한 변환이 이루어지지 않는다.

매개변수, 변수 호이스팅

//원본
function a(x) {
  console.log(x)
  var x; 
  console.log(x)
  var x = 2;
  console.log(x)
}
a(1)

함수 내부 코드보다 인자의 선언/할당이 먼저 이뤄진 것과도 같아 아래의 코드로 바꿨다.

function a() {
	var x = 1;
  console.log(x)
  var x; 
  console.log(x)
  var x = 2; 
  console.log(x)
}
a()

호이스팅이 이뤄지면 변수는 선언부만 올라가고, 할당부는 제자리에 남는다.

//호이스팅 끝
function a() {
	var x;
	var x;
	var x;

	x = 1;
  console.log(x)
  console.log(x)
  x = 2;
  console.log(x)
}
a(1)

호이스팅을 알기전엔 원본 코드의 결과가 1, undefined, 2라고 예상할 수 있지만 호이스팅을 알게된 지금은 1, 1, 2라는 결과를 예상할 수 있다.

함수 선언 호이스팅

//원본
function a() {
	console.log(b);
	var b = 'bbb';
	console.log(b);
	function b() {}
	console.log(b);
}
a();

호이스팅 시 변수명, 함수 선언의 정보가 올라간다. 그럼 아래의 형태가 된다.

//호이스팅 끝
function a() {
	var b	
	function b() {} //(1) var b = function b() {}

	console.log(b); //함수b 출력
	b = 'bbb';
	console.log(b); //'bbb'
	console.log(b); //'bbb'
}
a();

함수명으로 선언한 b라는 변수에 함수를 할당한 것과도 같기에, 주석(1)처럼 여길 수도 있다.

함수 선언문과 함수 표현식

function a () {} // 함수 선언문, 함수명이 변수명
var a = function () {} // (익명) 함수 표현식, 변수명이 함수명
var a = function b() {} // 기명 함수 표현식, 변수명 함수명 따로

함수 선언문: 함수 정의부만 있고, 할당 명령은 없다.

(익명) 함수 표현식: 정의한 함수를 변수에 할당한다.

기명 함수 표현식: 함수명을 정의한 함수를 변수에 할당한다.

  • 외부에서는 함수명으로 함수를 호출할 수 없다. 즉, a함수 선언시 실행되지만 b함수는 에러가 발생한다.

함수 선언문과 함수 표현식의 차이

//원본
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;
}

위 코드를 봤을 땐 콘솔창에 3, 12가 잘 출력될거 같지만 아니다.

//호이스팅 끝
var sum = function sum (a, b) {
	return a + b;
}
var mutiply;

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

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

위 코드는 호이스팅이 완료된 상태이다.
함수 선언문은 함수 전체가 올라가지만, 함수 표현식은 함수를 변수에 할당했기 때문에 변수 선언부만 올라가고 할당부는 제자리에 남는다. 그래서 3이 출력되고 mutiply is not a function이란 에러가 출력된다.

따라서 함수 표현식은 선언 이전에 호출할 수 없어서 실수를 미연에 방지할 수 있다.

2-3-2 스코프, 스코프 체인, outerEnvironmentReference

스코프: 식별자의 유효범위

A경계 외부에서 선언된 변수는 A경계 내부,외부 모두 접근이 가능하지만, A경계 내부에서 선언한 변수는 A경계 내부에서만 접근이 가능하다.

스코프 체인: outerEnvironmentReference를 통해 식별자의 유효범위를 안에서 밖으로 검색하는 것.

스코프 체인

”선언하다”라는 행위가 일어나는 상황은 콜스택 상에서 어떤 실행 컨텍스트가 활성화된 상태뿐이다.

함수를 선언하는 행위도 하나의 코드이며, 모든 코드는 실행 컨텍스트가 활성화 상태일 때 실행된다.

A함수{ B함수{ C함수{}}} 이런식의 함수가 있다하면
C함수의 outerEnvironmentReference는 B함수의 LexicalEnvironment를 참조한다.
B함수 LexicalEnvironmentouterEnvironmentReference는 A함수의 LexicalEnvironment를 참조한다.

outerEnvironmentReference는 선언된 시점의 LexicalEnvironment만 참조하기 때문에 가까운 요소부터 차례로 접근해서 스코프 체인 상 먼저 발견된 식별자에만 접근한다.

변수 은닉화: 특정 함수 내부에 a변수를 선언하면 외부에서 선언한 동일한 a변수에는 접근할 수 없는 것.

04 this

실행 컨텍스트 thisbinding에는 this로 지정된 객체가 저장된다. 실행 컨텍스트 활성화 시 this가 지정되지 않았다면, this에 전역 객체가 지정된다.

0개의 댓글