본문 바로가기

자스핑

[week 02] 실행 컨텍스트와 스코프, 호이스팅

실행 컨텍스트 : 자바스크립트의 동작 원리를 담고 있는 핵심 개념

실행 컨텍스트 : 소스코드를 실행하는데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역

 

실행 컨텍스트를 이해하면 알 수 있는 것

  • js가 스코프를 기반으로 식별자와 식별자에 바인딩된 값(식별자 바인딩)을 관리하는 방식
  • 호이스팅이 발생하는 이유
  • 클로저의 동작 방식
  • 태스트 큐와 함께 동작하는 이벤트 핸들러
  • 비동기 처리의 동작 방식

(나는 아직 모름;; 차차 알아가자)

4가지 소스 코드 타입

타입을 구분하는 이유는 소트코드의 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리하는 내용이 다르기 떄문에 구분하는 것이다.

 

📌 전역 코드

  • 전역코드는 전역 스코프를 생성한다.
  • var 키워드로 생성된 전역 변수, 함수 선언문으로 정의된 전역 함수를 전역 객체의 프로퍼티와 메서드로 바인딩 된다.
  • 전역 변수와 전역 함수를 참조하기 위해 전역 실행 컨텍스트가 생성되어 전역 객체의 프로퍼티를 탐색하여 값을 반환한다.

📌 함수 코드

  • 함수 코드는 지역 스코프를 생성한다.
  • 지역 변수, 매개변수, arguments 객체를 관리해야한다.
  • 지역 스코프는 항상 전역 스코프와 연결된다.
  • 지역 스코프와 전역 스코프를 연결하기 위해 함수 코드가 평가 되면 함수 실행 컨텍스트가 생성되어, 이 컨텍스트는 함수 내부에서 선언된 변수와 상위 스코프(외부 렉시컬 환경)에 대한 참조를 포함한다. ⇒ 이 구조가 스코프 체인을 형성해 변수 참조 시 상위 스코프까지 접근할 수 있도록 만든다.

🔸 스코프 체인은 밑에서 나오지만 간단하게 설명하면 스코프가 계층적으로 연결된 것!

 

📌 eval 코드

  • eval 코드는 strict mode에서 자신만의 독자적인 스코프를 생성
  • 이를 위해 eval 코드가 평가되면 eval 실행 컨텍스트가 생성된다.

 📌 모듈 코드

  • 모듈 코드는 모듈별로 독자적인 모듈 스코프를 생성(import로 가져온 외부 모듈의 식별자는 이 환경에 포함)
  • 이를 위해 모듈 코드가 생성되면 모듈 실행 컨텍스트가 생성된다. </aside>

소스코드의 평가와 실행

자바스크립트 엔진은 소스코드 평가, 소스코드 실행 과정으로 나누어 처리한다.

 

📌 소스코드 평가 과정 : 실행 컨텍스트를 생성하고 변수, 함수 등의 선언문만 먼저 실행하여 생성된 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록

 

📌 소스코드 실행 과정(런타임): 선언문을 제외한 소스코드가 순차적으로 실행, 변수나 함수의 참조와 같이 소스코드의 실행에 필요한 정보는 실행 컨텍스트가 관리하는 스코프에서 검색해서 취득한다.

변수 값의 변경 등 소스코드의 실행 결과는 다시 실행 컨텍스트가 관리하는 스코프에 등록


 

실행 컨텍스트 : 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역.

 

  • 실행 컨텍스트는 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 매커니즘으로 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.
  • 각 실행 컨텍스트는 하나의 렉시컬 환경을 가지며 변수, 함수의 선언 및 스코프 체인을 관리한다.
  • 식별자와 스코프는 실행 컨텍스트의 렉시켤 환경으로 관리하고 코드 실행 순서는 실행 컨텍스트 스택으로 관리한다.
렉시컬 환경으로 관리하는 것  실행 컨텍스트 스택으로 관리하는 것
식별자 코드 실행 순서
스코프  

 

🔸 식별자는 변수, 함수, 객체의 이름을 나타내는 값이다. 프로그래밍에서 특정 값을 참조할 때 사용하는 이름으로 식별자를 통해 데이터에 접근한다.

🔸 스코프는 변수, 함수, 객체 등이 접근할 수 있는 범위를 의미한다.

 

렉시컬 환경 : 실행 컨텍스트를 구성하는 컴포넌트 중 하나로 식별자와 식별자에 바인딩된 값. 그리고 상위 스코프에 대한 참조를 기록하는 자료구조이다.
  • 실행 컨텍스트가 생성될 때마다 렉시컬 환경이 생성된다.
  • 렉시컬 환경은 코드 실행 시점에서 변수 식별자를 저장하고 이를 참조할 때 사용하는 저장소 역할 

 

렉시컬 환경은 다음 두 가지 구성 요소로 이루어져 있다.

  1. 환경 레코드(Environment Record)
    • 키와 값을 가지는 객체 형태의 스코프(전역, 함수 ,블록 스코프)를 생성하고 스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩 된 값을 관리하는 저장소
    • 각 식별자를 키로 그에 바인딩된 값을 값으로 저장합니다.
    • 자바스크립트는 실행 과정에서 선언문만 먼저 실행하여 환경 레코드에 식별자를 등록하고 초기화는 이후에 이루어진다.
    ⇒ 렉시컬 환경은 스코프를 구분하여 식별자를 등록하고 관리하는 저정소 역할을 하는 렉시컬 스코프의 실체다.호출 위치와 관계없이 함수가 어디서 정의되었는지에 따라 상위 스코프가 결정되는 것

    🔸 렉시컬 스코프 : 코드가 정의된 위치에 따라 스코프가 결정되는 자바스크립트의 스코핑 규칙
  2. 외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference)
    • 외부 렉시컬 환경에 대한 참조는 상위 스코프를 가리킨다.
    • 이때 상위 스코프란 외부 렉시컬 환경, 즉 해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 엑시컬 환경을 의미.
    • 외부 렉시컬 환경에 대한 참조를 통해 단방향 링크드 리스트인 스코프 체인을 구현

실행 컨텍스트 스택

  • 실행 컨텍스트는 스택 자료구조로 관리된다.
  • 실행 컨텍스트 스택의 최상위에 존재하는 실행 컨텍스트는 언제나 현재 실행 중인 코드의 실행 컨텍스트다.

스코프 scope(유효범위)

식별자(변수 이름, 함수 이름, 클래스 이름 등)를 참조할 수 있는 유효한 범위

  • 스코프는 변수와 함수에 깊은 관련이 있다
  • 식별자를 검색할 때 사용하는 규칙이다
    • 식별자 결정(identifier resolution) : 이름이 같은 변수 중에서 어떤 변수를 참조해야 할 지를 결정하는 것
  • 스코프는 실행 컨택스트와 깊은 관련이 있다.
  • 스코프 내에서 식별자의 변수 이름은 중복될 수 없지만(유일) 다른 스코프에서는 같은 변수이름의 식별자가 사용 가능하다. → 스코프는 네임스페이스다.

스코프의 종류

  • 변수는 자신이 선언된 위치에 의해 자신의 스코프(유효한 범위)가 정해진다

구분 설명 스코프 변수

전역 코드의 가장 바깥 영역 전역 스코프 전역 변수
지역 함수 몸체 내부 지역 스코프 지역 변수

스코프 체인

스코프가 계층적으로 연결된 것

  • 중첩 함수(nested function) : 함수 몸체 내부에서 정의한 함수
  • 외부 함수(outer function) : 중첩 함수를 포함하는 함수

함수의 중첩에 따라 스코프도 중첩이 된다.

⇒ 즉 스코프가 함수의 중첩에 의해 계층적 구조를 가진다.

스코프 페인을 통해 참조할 변수를 검색하는(식별자 결정) 방향은 변수를 참조하는 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.

⇒ 따라서 상위 스코프에서 선언한 변수를 하위 스코프에서도 참조할 수 있는 것이다.

  • 스코프 체인은 실행 컨텍스트의 렉시컬 환경을 단방향으로 연결한 것이다.
 📌 렉시컬 환경(lexical enviroment) 코드가 어디서 실행되며 주변에 어떤 코드가 있는지 코드의 문맥으로 렉시컬 환경이 이루어 진다.
  • 스코프 체인으로 연결된 스코프의 계층적 구조는 부자 관계로 이뤄진 상속(ineritace)와 유사하다.
  • ⇒ 상속을 통해 부모의 자산을 자식이 자유롭게 사용 가능 but, 부모는 자식의 자산을 사용하지 못함.

함수 레벨 스코프

  • 블록 레벨 스코프(block level scope)
  • : 모든 코드 블록(if, for, while …)이 지역 스코프를 생성한다.
  • 함수 레벨 스코프(function level scope)ex) var 키워드로 선언된 변수
  • : 함수에 의해서만 지역 스코프가 생성한다.

  1. 동적 스코프(dynamic scope)
    • 함수를 어디서 호출 했는지에 따라 함수의 상위 스코프를 결정한다.
    • 함수가 호출되는 시점에 동적으로 상위 스코프를 결정한다.
  2. 렉시컬 스코프(lexical scope), 정적 스코프(static scope)
    • 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정한다.
    • 함수 정의가 평가되는 시점에 상위 스코프가 정적으로 결정된다.

렉시컬 스코프

자바스크립트는 렉시컬 스코프를 따른다.

  • 함수의 상위 스코프는 함수 정의(함수 선언문, 함수 표현식)가 실행될 때 정적으로 결정된다.
    • 함수 선언문으로 함수를 정의하면 런타임 이전에 함수 객체가 먼저 생성된다.
    • 함수 객체는 결정된 상위 스코프를 기억한다.
    • 함수가 호출될 때마다 상위 스코프를 참조한다.
  • 렉시컬 스코프는 클로저와 깊은 관계가 있다.

변수의 실행 시점과 변수 호이스팅

자바스크립트의 모든 선언문은 런타임 이전 단계에서 실행된다.

자바스크립트 엔진은 1. 소스코드의 평가 2. 소스코드의 실행 과정을 나누어서 처리한다.

  1. 소스코드의 평가 (선언문)
  • 실행 컨텍스트를 생성
  • 선언문을 먼저 실행 → 식별자를 키로 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록
  1. 소스코드의 실행 (선언문을 제외한 문)
  • 런타임 시작
  • 실행에 필요한 정보(변수나 함수의 참조 등)를 실행 컨텍스트가 관리하는 스코프에서 검색해서 취득
  • 값의 변경이나 실행 결과는 다시 실행 컨텍스트에 등록
📌 호이스팅 (hoisting) 식별자(변수, 함수, 클래스 등)를 어느 위치에 선언하든지 식별자 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트의 특징

 

var 키워드로 선언한 변수의 문제점

  1. 변수 중복 선언을 허용한다.
  2. 함수 레벨 스코프만 지원한다.
    1. 의도치 않게 전역 변수가 중복 선언될 수 있음
  3. var 변수의 선언은 “선언 단계”와 “초기화 단계”가 동시에 진행된다
    1. 변수 호이스팅에 의해서 변수 선언문 이전에 참조할 수 있지만 할당문 이전에 참조하면 에러 없이 항상 undefined를 반환한다.

let 키워드

  • 같은 스코프 내에서 변수 중복 선언 금지
  • 블록 레벨 스코프를 따른다.
  • 선언 단계”와 “초기화 단계”가 분리되어 진행된다.
    • 런타임 이전에 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 진행된다 ⇒ 초기화 단계 이전에 변수 접근 시 참조 에러가 발생한다.(TDZ가 발생)
    • ⇒ 변수 호이스팅이 발생하지 않는 것처럼 보인다.
📌 일시적 사각지대(temporal dead zone, TDZ) : 스코프의 시작 지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간

 

  • let, const로 선언한 전역 변수는 전역 객체 window의 프로퍼티가 아니다.

const 키워드

  • 상수(재할당이 금지된 변수)를 선언하기 위해서 사용한다.
  • 반드시 선언과 동시에 초기화를 해야한다.
  • 원시(pass-by-value/ 값에 의한 전달)값을 할당한 경우 값 변경 불가
  • 객체(pass-by-reference/ 참조에 의한 전달)를 할당한 경우 값 변경 가능 - 재할당 없이 변경가능하기 때문에