책 정리/코어 자바스크립트
2. 실행 컨텍스트
Rulu_
2023. 4. 21. 11:45
실행 컨텍스트
- 실행 컨텍스트: 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
- JS의 동적언어로서의 성격을 가장 잘 파악할 수 있는 개념
2-1 실행 컨텍스트란?
- 스택: 출입구가 하나뿐인 깊은 우물 같은 데이터 구조
- a-b-c-d로 넣었다면 d-c-b-a로 꺼내야함
- 스택이 넘치면 에러를 던짐
- 큐: 양쪽 모두 열려있는 파이프
- 보통 한쪽은 출력만 한쪽은 입력만 담당
- a-b-c-d로 넣었다면 a-b-c-d로 꺼냄
- 동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성(전체 코드의 환경과 순서를 보장)
- → 콜 스택에 쌓아올림 → 가장 위에 쌓여있는 컨텍스트와 관련있는 코드들을 실행하는 식
- 동일한 환경? 하나의 실행 컨텍스트를 구성할 수 있는 방법
- 전역공간, eval()함수, 함수 등등
- 자동으로 생성되는 전역공간과 eval()을 제외하고 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것
- 한 실행 컨텍스트가 콜 스택의 맨 위에 쌓이는 순간이 곧 현재 실행할 코드에 관여하게 되는 시점
- 기존의 컨텍스트는 새로 쌓인 컨텍스트보다 아래에 위치할 수 밖에 없기 때문
- 실행 컨텍스트가 활성화 될 때 JS엔진은 해당 컨텍스트에 관련된 코드를 실행하는 데 필요한 환경 정보를 수집해 실행 컨텍스트 객체에 저장
- 이 객체는 JS엔진이 활용하기 위함이지 개발자가 확인 불가능
2-2 VariableEnvironment
- 여기에 담기는 내용은 LexicalEnvironment와 같지만 최초 실행 시의 스냅샷을 유지한다는 점이 다름
- 실행 컨텍스트를 생성할 때 VariableEnvironment에 정보를 먼저 담고 이를 복사해서 LexicalEnvironment를 만들고 이후에는 LexicalEnvironment를 주로 활용
- 둘은 초기화 과정에는 사실상 완전히 동일하고 이후 코드 진행에 따라 달라짐
2-3 LexicalEnvironment
- 어휘적 환경, 정적 환경 이라는 단어로 표현하지만 사전적인 이 더 어울림
- 컨텍스트를 구성하는 환경 정보들을 사전에서 접하는 느낌으로 모아놓은 것
- ex.) 현재 컨텍스트 내부에 a,b,c같은 식별자가 있고 그 외부 정보는 B를 참조하도록 구성됨
2-3-1 environmentRecord와 호이스팅
- environmentRecord에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장.
- 컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우 그 함수자체, var로 선언된 변수의 식별자 등이 식별자에 해당
- 컨텍스트 내부 전체를 처음부터 끝까지 순서대로 수집
- 코드가 실행되기 전에 JS엔진은 이미 해당 환경에 속한 코드의 변수명을 모두 알고있음
- 호이스팅: JS엔진이 편의상 끌어올린 것으로 간주하자
호이스팅 규칙
- environment Record는 현재 실행될 컨텍스트의 대상 코도 내에 어떤 식별자들이 있는지에만 관심이 있고, 각 식별자에 어떤 값이 할당될 것인지는 관심이 없음
- 변수를 호이스팅할 때 변수명만 끌어올리고 할당 과정은 원래 자리에 그대로 남겨둠.(매개변수도 마찬가지)
- 변수는 선언부와 할당부를 나누어 선언부만 끌어올림, 함수선언은 함수 전체를 끌어올림.
- 함수 선언문은 전체를 호이스팅, 함수 표현식은 변수 선언문만 호이스팅
- 동일한 변수명에 서로 다른 값을 할당할 경우 나중에 할당한 값이 먼저 할당한 값을 덮어씌움
- 전역공간에 동명의 함수가 여럿 존재하는 상황이라 하더라도 모든 함수가 함수 표현식으로 정의돼 있다면 문제를 일으키지 않을 것
2-3-2 스코프, 스코프 체인, outerEnvironmentReference
- 스코프: 식별자에 대한 유효범위
- ES5까지의 JS는 특이하게도 전역공간을 제외하면 오직 함수에 의해서만 스코프가 생성됨.
- 스코프 체인: 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것
- outerEnvironmentReference가 이를 도움
- 스코프 체인
- outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조
- ‘선언하다’라는 행위가 실제로 일어날 수 있는 시점이란 콜 스택 상에서 어떤 실행 컨텍스트가 활성화 된 상태일 뿐.→ 모든 코드는 실행 컨텍스트가 활성화 상태일 때 실행
- → 어떤 함수를 선언하는 행위 자체도 하나의 코드임.
- outerEnvironmentReference는 연결리스트 형태를 띔
- 선언 시점의 LexicalEnvironment를 계속 찾아 올라가면 마지막엔 전역 컨텍스트의 LexicalEnvironment가 있을 것.
- 각 outerEnvironmentReference는 오직 자신이 선언된 시점의 LexicalEnvironment만 참조하고 있으므로 가장 가까운 요소부터 차례대로만 접근 가능 → 다른 순서로 접근하는 것은 불가능.
- 여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능
- 스코프 체인 상에 있는 변수라고 해서 무조건 접근 가능한 것은 아니다.
- 변수 은닉화: inner함수 내부에서 a변수를 선언했기 때문에 전역 공간에서 선언한 동일한 이름의 a변수에는 접근할 수 없음.
- 전역변수와 지역변수
- 전역변수: 전역 공간에서 선언한 변수
- 지역변수: 함수 내부에서 선언한 변수
- 코드의 안정성을 위해 가급적 전역변수 사용을 최소화하고자 노력하는 것이 좋음
this
- 실행 컨텍스트의 thisBinding에는 this로 지정된 객체가 저장
- 실행 컨텍스트 활성화 당시에 this가 지정되지 않은 경우 this에는 전역 객체자 저장