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

박은정·2021년 11월 15일
1

자바스크립트

목록 보기
16/25
post-thumbnail

컨텍스트가 문맥을 나타내는데,
실행 컨텍스트 Execution Context란, Javascript 코드가 실행할 코드에 제공할 환경 정보들을 모아 놓는 환경을 말한다.

실행 컨텍스트가 가지고 있는 정보

여기서 말하는 실행 컨텍스트가 모아놓는 정보란, 코드를 실행하기 위한 여러가지 정보를 말하는데

  • 어떤 변수가 있고, 어떤 변수를 호이스팅할지
  • 스코프 및 스코프 체인이 어떤지
  • this는 어디에 어떻게 binding되는지 등등

대표적으로 3가지 분류로 구분할 수 있다

1. VarialeEnvironment

  • 변수객체 Vairable Object라고도 한다
  • LexicalEnvironment와 동일하지만 맨 처음으로 실행했을 때의 스냅샷을 유지한다
  • VarialeEnvironment에 정보를 먼저 담은 뒤, 이를 그대로 복사해서 LexicalEnvironment를 만들고, 이후에는 LexicalEnvironment만 활용하게 된다

2. LexicalEnvironment

실행 컨텍스트도 하나의 객체로서, 객체 안에 환경 정보가 다 있기 때문에
변수, 매개변수, 인자, 함수 선언 등의 정보를 가지고 있다

  1. Environment Record
    • 코드가 실행되기 전에 정보를 모두 수집해서 변수와 함수 선언 등을 저장한다
    • 자바스크립트 엔진은 Hoisting 에 의해 코드가 실행되기 전에 코드의 변수명을 모두 알고 있다
  2. Outer
    • 스코프 체이닝 에 대한 정보를 담고 있다
    • 실행 컨텍스트에서 작업을 끝내고 다른 변수(함수 내부말고, 다른 함수에서 선언된 변수)를 참조할 수 있도록 정보를 가지고 있다

3. ThisBinding

this로 지정된 객체가 저장된다
실행 컨텍스트가 활성화했을 때, this가 지정되지 않은 경우 this = global object로 지정된다
함수를 호출하는 방법에 따라 this에 지정되는 객체가 다르다

호이스팅 Hoisting

호이스팅의 개념

호이스팅이란, 간단히 말하자면 변수의 선언부는 끌어올리고, 할당은 코드가 실행되는 시점에서 진행한다고 할 수 있겠지만
더 정확히 말하자면, 실행 컨텍스트 상에서 LexicalEnvironment 안에 이 함수가 어떻게 쓰이는지 정보를 수집하고 시작하는 현상

호이스팅의 작동방식

var x = 1; 
console.log(x + " " + y); // '1 undefined'
var y = 2;

이런 상황에서 다른 프로그래밍 언어라면 y is not defined 라는 오류가 발생했겠지만,
자바스크립트에서는 호이스팅이라는 특성 덕분에 undefined 라는 값이 할당된 것을 볼 수 있다.
실제로 이렇게 작동하지는 않겠지만 이해를 돕기 위해 자바스크립트 엔진에서 처리하는 과정을 살펴보자면,

// === 호이스팅 작동 방식 ===
var x = 1; // Initialize x
var y; // Declare y
console.log(x + " " + y); // '1 undefined'
y = 2; // Initialize y

함수 선언식과 함수 표현식에서의 호이스팅

함수 선언문 (function declaration)

  • function 키워드를 통해 함수를 정의하는 것
  • function 정의만 존재하고 별도의 할당 명령이 없다
function a() { } 

이러한 함수의 선언문에서 함수를 정의하기 전에 먼저 선언했는데 에러가 발생하지 않는다

catName("Chloe");

function catName(name) {
  console.log("My cat's name is " + name);
}

// 위 코드의 결과는: "My cat's name is Chloe"

함수 표현식 (function expression)

표현식은 자바스크립트 말고도 그 밖의 다른 프로그래밍 언어에서도 다루는 개념으로, 값이라고 생각하면 좋다

  • function 키워드로 정의한 함수를 값으로 표현해서 다시 변수에 할당하는 것
  • 표현식 : 자바스크립트 인터프리터가 계산하여, 값을 구할 수 있는 자바스크립트 구절
  • 리터럴 : 이러한 값을 표현하는 것

리터럴에 대한 내용은 나중에 다시 다루려 합니다

// 1. 익명함수를 변수에 할당
var a = function() { } 
// const a = () => {} 

// 2. 이름을 준 상태에서 변수에 할당
var b = function success() { } 

a();
b();
success(); // error : b 함수 내부에서만 sucess 함수명에 접근할 수 있다

익명함수를 변수에 할당하기 전에 호출하면 사용할 수 없다

console.log(notHoisted) // undefined
notHoisted(); // TypeError: notHoisted is not a function

var notHoisted = function() {
   console.log('bar');
};

let, const의 호이스팅 차이점

  1. 변수 수정 가능의 유무
  2. 보통 var는 호이스팅이 되지만 let & const는 호이스팅이 되지 않는다고 하지만,
  3. 호이스팅이 어떻게 쓰일 지 수집하고 시작하는 현상이라는 개념으로 봤을 때, let과 const도 호이스팅은 되지만 실제로 데이터가 할당되서 사용되기 전까지는 TDZ에 있다.

Temporal Dead Zone (TDZ)

  1. let, const로 사용된 변수 역시 LexicalEnvironment에서 사용할 변수들을 호이스팅을 하다보니
  2. 변수가 쓰일지 알긴 알지만, 사용하지 못하도록 막아 놓은 것이다.
  3. 이렇기 때문에 let, const는 실행되기 전에 엑세스할 수 없고, 이러한 단계나 공간을 TDZ라고 한다
x = 3;
let x = 1;
  • 만약 TDZ라는 것이 없고 호이스팅이라는 동작이 되지 않았다면, x is not defined라는 에러를 봤겠지만,
    • 실제로는 초기화하기 전에 x 변수에 접근하지 말라는 의미의 Uncaught ReferenceError: Cannot access 'x' before initialization 라는 에러가 발생한다.

스코프 (Scope)

  • 모든 프로그래밍 언어에서 적용되는 개념
  • 변수가 살아있는, 유효한 범위
  • 만약 스코프가 없다면 코드 전체에서 동일한 변수나 식별자를 사용하면 안된다
var x = 'global';

function foo () {
  var x = 'function scope';
  console.log(x);  // function scope
}

foo();
console.log(x);   // global

변수가 살아있는 범위 스코프를 기준으로 함수로 생각하자면 global xfoo() 내부의 x는 다르다

스코프의 종류

1. 전역 스코프 (Global Scope)

  • 가장 바깥에서 선언하고 할당했다.
  • 코드 어디에서든 참조가 가능하다.
  • var로 선언한 변수는 전역 객체에 속한다 (=전역 객체의 프로퍼티가 된다)
  • 프론트엔드에서의 전역 스코프는 브라우저라고 생각하면 된다
    - Clinet (브라우저)의 전역객체 : window
    • Node.js에서의 전역객체 : global
var a = '안녕';

console.log(a); // 안녕
console.log(window.a); // 안녕 
  • 전역에서 선언한 변수는 window의 프로퍼티가 되기 때문에 어디에서나 접근이 가능하다
  • 평소에는 쓸 일이 없긴 하지만, 전역으로 라이브러리를 선언할 때 종종 사용된다.
  • 단, 라이브러리도 누구나 사용할 법한 변수로 선언하는 것이 아니라 정말 고유한 이름으로 선언을 해줘야 한다.

2. 지역 스코프 (Local Scope)

  • 자바스크립트는 다른 언어와 달리 스코프의 범위가 함수 블록 이다. : 함수에 의해서만 스코프가 생성된다
  • 다른 언어에서는 { } 블록 이 스코프의 단위이기 때문에 특이하다
  • 그래서 let, const에서부터는 스코프의 단위가 { } 블록이 되었다.
if (true) {
  var x = 5;
}

console.log(x);  // 5
{ 
	let x = 1; 
}

console.log(x); //Uncaught ReferenceError: x is not defined

이런 코드에서 스코프를 한정짓고 싶을 때 즉시실행함수 방식을 사용하면 된다

(function () {
  var x = 5;
})();

console.log(x);  // Uncaught ReferenceError: x is not defined

스코프 체인 (Scope Chain)

변수가 해당 스코프에서 유효하지 않을 때, 앞에서부터 바깥으로 차례로 검색해 나가는 것이다.

function sum() {

  var a = 3
	var b = 5;

  function inner() {
    var b = 7;
		var c = 11;

    a = a + b + c;    // a = 3, b = 7, c = 11
		console.log(a);  // 21
  };

	console.log(a);  // 3
  inner();
	console.log(a);  // 21
};

sum();
console.log(a); // Uncaught ReferenceError: a is not defined
profile
새로운 것을 도전하고 노력한다

0개의 댓글