본문 바로가기

2022-2 웹개발 스터디

[모던 JS] CH23 실행컨텍스트, CH13 스코프

CH23. 실행컨텍스트

23.1 소스코드의 타입

23.2 소스코드의 평가와 실행

- 소스 평가 과정에서는 실행 컨텍스트를 생성하고

  변수, 함수 등의 선언문만 먼저 실행하여 생성된 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프에 등록함

23.3 실행 컨텍스트의 역할

1. 전역 코드 평가

- 전역 코드 실행하기 앞서 전역 코드 평가 과정을 거침

- 소스코드 평가 과정에서는 선언문만 먼저 실행됨

- var 키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 프로퍼티와 메서드가 됨

2. 전역 코드 실행

- 런타임이 시작되어 전역 코드가 순차적으로 실행되기 시작함

- 전역 변수에 값이 할당되고 함수가 호출됨

3. 함수 코드 평가

- 함수 호출에 의해 코드 실행 순서가 변경되어 함수 내부로 진입하면 함수 내부의 문들을 실행하기에 앞서 함수 코드 평가 과정을 거침

- 매개변수와 지역 변수 선언문이 먼저 실행되고, 그 결과 생성된 매개변수와 지역 변수가 실행 컨텍스트가 관리하는 지역 스코프에 등록됨

- 함수 내부에서 지역 변수처럼 사용할 수 있는 arg 객체가 생성되어 지역 스코프에 등록되고 this 바인딩도 결정됨

4. 함수 코드 실행

- 런타임이 시작되어 함수 코드가 순차적으로 실행되기 시작함

- 매개변수와 지역변수에 값이 할당되고 console.log 메서드가 호출됨

23.4 실행 컨텍스트 스택

const x = 1;

function foo(){
    const y = 2;
    
    function bar() {
        const z = 3;
        console.log(x + y + z);
    }
    bar();
}

foo();

- 먼저 전역코드를 평가하여 전역 실행 컨텍스트를 생성

- 함수가 호출되면 함수 코드를 평가하여 함수 실행 컨텍스트를 생성

- 이때 생성된 실행 컨텍스트는 스택 자료구조로 관리됨 -> 실행 컨텍스트 스택

23.5 렉시컬 환경

렉시컬 환경?

- 식별자와 식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트

- 키와 값을 갖는 객체 형태의 스코프(전역, 함수, 블록 스코프)를 생성하여 식별자 키로 등록하고 식별자에 바인딩된 값을 관리함

 

렉시컬 환경은 두 개의 컴포넌트로 구성됨

1. 환경 레코드

: 스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩된 값을 관리하는 저장소

: 환경 레코드는 소스코드의 타입에 따라 관리하는 내용에 차이가 있음

 

2. 외부 렉시컬 환경에 대한 참조

: 상위 스코프를 가리킴

: 외부 렉시컬 환경에 대한 참조를 통해 단방향 링크드 리스트인 스코프 체인을 구현함

23.6 실행 컨텍스트의 생성과 식별자 검색 과정

23.6.1 전역 객체 생성

- 전역 코드가 평가되기 이전에 생성됨

23.6.2 전역 코드 평가

- 소스코드가 로드되면 자바스크립트 엔진은 다음과 같은 순서로 전역 코드를 평가함

23.6.3 전역 코드 실행

23.6.4 foo 함수 코드 평가

- foo 함수가 호출되면 전역 코드의 실행을 일시 중단하고 foo 함수 내부로 코드의 제어권이 이동함

- 아래와 같은 순서로 진행

23.6.5 foo 함수 코드 실행

- 식별자 결정을 위해 실행 중인 실행 컨텍스트의 렉시컬 환경에서 식별자를 검색하기 시작함

23.6.6 bar 함수 코드 평가

- bar 함수가 호출되면 bar 함수 내부로 코드의 제어권이 이동함

23.6.7 bar 함수 코드 실행

 

! 다음 코드의 실행순서

console.log(a + b + x + y + z);

1. console 식별자 검색

2. log 메서드 검색

3. 표현식 a + b + x + y + z의 평가

4. console.log 메서드 호출

23.6.8 bar 함수 코드 실행 종료

- console.log 메서드가 호출되고 종료하면 더는 실행할 코드가 없으므로 bar 함수 코드의 실행이 종료됨

- bar 함수 실행 컨텍스트가 소멸되었다 하더라도 만약 bar 함수 렉시컬 환경을 누군가 참조하고 있다면 bar 함수 렉시컬 환경은 소멸하지 않음

23.6.9 foo 함수 코드 실행 종료

- bar 함수가 종료하면 더 이상 실행할 코드가 없으므로 foo 함수 코드의 실행이 종료됨

- 실행 컨텍스트 스택에서 foo 함수 실행 컨텍스트가 팝되어 제거되고 전역 실행 컨텍스트가 실행 중인 실행 컨텍스트가 됨

23.6.10 전역 코드 실행 종료

foo 함수가 종료되면 더 실행한 전역 코드가 없으므로 전역 코드의 실행이 종료되고 전역 실행 컨텍스트도 실행 컨텍스트 스택에서 팝되어 실행 컨텍스트 스택에는 아무것도 남아있지 않게 됨

23.7 실행 컨텍스트와 블록 레벨 스코프

let x = 1;

if (true) {
    let x = 10;
    console.log(x);
}

console.log(x);

- if 문의 코드 블럭이 실행되면 if 문의 코드 블록을 위한 블록 레벨 스코프를 생성해야 함

- 이를 위해 선언적 환경 레코드를 갖는 렉시컬 환경을 새롭게 생성하여 기존의 전여 렉시컬 환경을 교체함

- 이때 새롭게 생성된 if 문의 코드 블록을 위한 렉시컬 환경의 외부 렉시컬 환경에 대한 참조는

   if문이 실행되기 이전의 전역 렉시컬 환경을 가리킴

CH13. 스코프

13.1 스코프란?

- 변수는 자신이 선언된 위치에 의해 자신이 유효한 범위가 결정됨

- 변수뿐만 아니라 모든 식별자 해당

- 스코프는 식별자가 유효한 범위

- 자바 스크립트 엔진이 식별자를 검색할 때 사용하는 규칙

 

! var 키워드로 선언한 변수의 중복 선언

- var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언이 허용됨

- 의도치 않게 변수값이 재할당되어 변경되는 부작용을 발생시킴

- 하지만 let이나 const 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언을 허용하지 않음

13.2 스코프의 종류

13.2.1 전역과 전역 스코프

- 전역변수는 어디서든지 참조 가능

- 전역에 변수를 선언하면 전역 스코프를 갖는 전역변수

13.2.2 지역과 지역 스코프

- 지역?

: 함수 몸체 내부

- 지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효함

13.3 스코프 체인

- 함수는 중첩될 수 있으므로 함수의 지역 스코프도 중첩될 수 있음

: 즉, 스코프가 함수의 중첩에 의해 계층적 구조를 갖게됨

- 이처럼 모든 스코프는 하나의 계층적 구조로 연결됨

- 모든 지역 스코프의 최상위 스코프는 전역 스코프

- 변수를 참조할 때, 자바 스크립트 엔진은 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색함

13.3.1 스코프 체인에 의한 변수 검색

- 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조할 수 있지만,

- 하위 스코프에서 유효한 변수를 상위 스코프에서 참조할 수 없음

13.3.2 스코프 체인에 의한 함수 검색

- 스코프를 '변수를 검색할 때 사용하는 규칙'이라고 표현하기 보다는 '식별자를 검색하는 규칙'이라고 표현하는 편이 더 적합함

13.4 함수 레벨 스코프

- var 키워드로 선언된 변수는 오로지 함수의 코드 블록(함수 몸체)만을 지역 스코프로 인정함

- 이러한 특성을 함수 레벨 스코프라고 함

var x = 1;

if (true) {
    var x = 10;
}

console.log(x); //10

// 의도치 않게 변수 값이 변경되는 부작용

13.5 렉시컬 스코프

var x = 1;

function foo() {
    var x = 10;
    bar();
}

function bar() {
    console.log(x);
}

foo();
bar();

-> bar 함수는 전역에서 정의된 함수,

- 함수 선언문으로 정의된 bar 함수는 전역 코드가 실행되기 전에 먼저 평가되어 함수 객체를 생성함

- 이때 생성된 bar 함수 객체는 자신이 정의한 스코프, 즉 전역 스코프를 기억함

- bar 함수가 호출되면 호출된 곳이 어디인지 관계없이 언제나 자신이 기억하고 있는 전역 스코프를 상위 스코프로 사용함

-> 따라서 위 예제를 실행하면 전역 변수 x의 값 1을 두 번 출력하는 결과