1. 실행 컨텍스트란?
- 실행할 코드에 제공할 환경 정보들을 모아놓은 객체.
- 선언된 변수를 위로 끌어올린다. (호이스팅)
- 외부 환경 정보를 구성
- this 값을 설정
- 스택(stack)
- 마지막에 들어간게 첫번째로 나오는 구조
- 콜 스택(call stack)
- 필요한 환경 정보들을 모아 컨텍스트를 구성하고 이것을 stack의 한 종류인 콜 스택에 쌓아올린다. 가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경 및 순서를 보장할 수 있다.- 컨텍스트의 구성
- 구성 방법
a. 전역공간
b. eval()함수
c. 함수(흔히 실행 컨텍스트를 구성하는 방법) - 실행 컨텍스트 구성 예시
- 구성 방법
- 컨텍스트의 구성
// ---- 1번
var a = 1;
function outer() {
function inner() {
console.log(a); //undefined
var a = 3;
}
inner(); // ---- 2번
console.log(a);
}
outer(); // ---- 3번
console.log(a);
코드실행 → 전역(in) → 전역(중단) + outer(in) → outer(중단) + inner(in) → inner(out) + outer(재개) → outer(out) + 전역(재개) → 전역(out) → 코드종료
따라서 결과 값은 undefined, 1, 1이 순서대로 나온다.
- 실행 컨텍스트 객체의 실체(=담기는 정보)
- VariableEnvironment
a. 현재 컨텍스트 내의 식별자 정보(=record)를 갖고 있다.
b. 외부 환경 정보(=outer)를 갖고 있다.
c. 선언 시정 LexicalEnvironment의 snapshot - LexicalEnvironment
a. VariableEnvironment와 동일하지만, 변경사항을 실시간으로 반영한다. - ThisBinding
a. this 식별자가 바라봐야할 객체
- VariableEnvironment
2. VariableEnvironment, LexicalEnvironment
- VE vs LE
- 담기는 항목은 완벽하게 동일. But 스냅샷 유지여부는 다르다.- VE : 스냅샷을 유지
- LE : 스냅샷을 유지하지 않는다. 실시간으로 변경사항을 계속해서 반영한다.
==> 결과적으로 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담고, 이를 그대로 복사해서 LE를 만들고 이후에는 주로 LE를 활용
- 구성 요소
- VE, LE 모두 동일, environmentRecord 와 outerEnvironmentReference로 구성
- environmentRecord(=record)
- 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장된다.
- 함수에 지정된 매개변수 식별자, 함수자체, var로 선언된 변수 식별자 등
- outerEnvironmentReference(=outer)
3. LexicalEnvironment - environmentRecord(=record)와 호이스팅
- 개요
- 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장(수집)
- 수집 대상 정보: 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등
- 컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집
- 호이스팅
- 변수 정보 수집을 모두 마쳤더라도 아직 실행 컨텍스트가 관여할 코드는 실행 전의 상태
- 변수 정보 수집 과정을 이해하기 쉽게 설명한 '가상 개념'
- 호이스팅 규칙
- 매개변수 및 변수는 선언부를 호이스팅 한다.
- 함수 선언은 전체를 호이스팅한다.
- 함수 선언문 함수 표현식
- 함수 정의의 2가지 방식
a. fuction 정의부만 존재, 할당 명령어 없는 경우
b. 함수 표현식, 정의한 function 을 별도 변수에 할당하는 경우
(1) 익명함수표현식 : 변수명 b가 곧 변수명(일반적 case)
(2) 기명 함수 표현식 : 변수명은 c, 함수명은 d
c. d()는 c() 안에서 재귀적으로 호출될 때만 사용 가능하므로 사용성에 대한 의문
- 함수 정의의 2가지 방식
function a ()
a(); // 실행 ok
var b = function ()
b(); // 실행 ok
var c = function d ()
c(); // 실행 ok
d(); // 에러
* 함수 선언문 주의 사항
...
console.log(sum(3, 4));
// 함수 선언문으로 짠 코드
// 100번째 줄 : 시니어 개발자 코드(활용하는 곳 -> 200군데)
// hoisting에 의해 함수 전체가 위로 쭉!
function sum (x, y) {
return x + y;
}
...
...
var a = sum(1, 2);
...
// 함수 선언문으로 짠 코드
// 5000번째 줄 : 신입이 개발자 코드(활용하는 곳 -> 10군데)
// hoisting에 의해 함수 전체가 위로 쭉!
function sum (x, y) {
return x + ' + ' + y + ' = ' + (x + y);
}
...
var c = sum(1, 2);
console.log(c);
==> 결과 적으로 밑에서 함수 선언을 다시 함으로써 전체 코드에 영향을 주기 시작함
...
console.log(sum(3, 4));
// 함수 표현식으로 짠 코드
// 함수 선언부만 위로 쭉!
// 이 이후부터의 코드만 영향을 받아요!
var sum = function (x, y) {
return x + y;
}
...
...
var a = sum(1, 2);
...
// 함수 표현식으로 짠 코드
// 함수 선언부만 위로 쭉!
// 이 이후부터의 코드만 영향을 받아요!
var sum = function (x, y) {
return x + ' + ' + y + ' = ' + (x + y);
}
...
var c = sum(1, 2);
console.log(c);
==> 이렇게 함수 선언문이 아닌 함수 표현식을 통해 작성한다면 영향을 주지 않는다. 따라서 코드 협업을 할 때에는 함수 표현식을 활용하는 습관을 갖는게 좋다.
4. LexicalEnvironment(2) - 스코프, 스코프 체인, outerEnvironmentReference(=outer)
- 스코프
- 식별자에 대한 유효범위
- 대부분 언어에서 존재, 당연히 JS에서도 존재
- 스코프 체인
- outer는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조
==> 결론 : 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에게만 접근이 가능
- outer는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조
// 아래 코드를 여러분이 직접 call stack을 그려가며 scope 관점에서 변수에 접근해보세요!
var a = 1;
var outer = function() {
var inner = function() {
console.log(a); // 이 값은 뭐가 나올지 예상해보세요! 이유는 뭐죠? scope 관점에서!
var a = 3;
};
inner();
console.log(a); // 이 값은 또 뭐가 나올까요? 이유는요? scope 관점에서!
};
outer();
console.log(a); // 이 값은 뭐가 나올까요? 마찬가지로 이유도!
==> 각각의 실행 컨텍스트는 LE 안에 record와 outer를 가지고 있고, outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE정보가 다 들어있으니 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있다.
'JavaScript Dev. > Javascript' 카테고리의 다른 글
13. 콜백 함수와 동기/비동기 처리 (0) | 2023.10.23 |
---|---|
12. this(정의, 활용 방법, 바인딩, call, apply, bind) (1) | 2023.10.19 |
10. 데이터 타입 (0) | 2023.04.21 |
2023.04.15 - Number vs. parseInt (1) | 2023.04.15 |
2023.04.12 - <2주차 과제> (0) | 2023.04.12 |