호이스팅
이전에 실행컨텍스트에 대해 다루었었다.
https://muyeon95.tistory.com/317
실행 컨텍스트 요약
자바스크립트 코드를 실행하는데 필요한 환경 정보,
즉 변수 객체, 스코프 체인, this 에 관한 내용 등을 담고 있는 객체이다.
실행 컨텍스트는 크게 전역 컨텍스트와 함수 컨텍스트 2가지로 나뉘며, 자바스크립트 코드 실행이 시작되면 무조건 콜 스택에
전역 컨텍스트가 먼저 쌓이고, 그 위로 함수를 호출할 때마다 함수 컨텍스트가 생성된다.
각 컨텍스트가 생성될 때마다 실행에 필요한 환경정보(변수 객체, 스코프 체인, this)가 생성된다.
코드의 함수가 실행되면 함수 안의 변수들이 함수 컨텍스트 안의 변수 객체에서 값을 찾고, 없다면 스코프 체인을 따라 올라가며 찾게 된다.
그리고 함수의 실행이 마무리되면 해당 함수 컨텍스트는 콜 스택에서 제거된다.
함수의 실행이 모두 끝나서 페이지가 종료되면 가장 아래에 있던 전역 컨텍스트도 사라진다.
Record & 호이스팅
Record 를 가리키는 ECMA script 의 정식 명칭은 환경 레코드(Environment Record) 이다.
key:value 형태처럼 식별자와 식별자에 바인딩 된 값을 기록해두는 객체이다.
호이스팅은 선언문이 최상단으로 끌어올려지는 것처럼 선언 라인 이전에도 에러 없이 변수를 참조할 수 있는 현상이다.
호이스팅 발생 과정
1. 생성 단계 (Creation Phase)
자바스크립트 엔진은 코드를 실행하면 우선 전역 실행컨텍스트를 가장 먼저 생성해서 콜 스택에 넣는다.
그 후 전체 코드를 스캔한다. 이 과정에서 선언할 식별자 변수가 있다면 전역 실행 컨텍스트의 환경 레코드에 미리 선언해둔다.
식별자 변수가 var 키워드로 선언되었다면 undefined 로 초기화해두고 let/const 라면 따로 초기화를 진행하지 않는다.
2. 실행 단계 (Execution Phase)
위에서 기록해둔 선언문 라인을 제외한 나머지 코드를 순차적으로 실행한다.
필요한 경우, 생성 단계에서 환경 레코드에 기록해 둔 식별자를 참조하거나 또는 값을 업데이트(재할당)한다.
호이스팅 종류
1. 변수 호이스팅 (var, let/const)
변수를 var 로 선언한 경우
자바스크립트 엔진이 전체 코드를 스캔할 때 undefined 를 할당해 환경 레코드에 기록한다.
console.log() 의 log() 도 함수이기 때문에 자바스크립트 엔진에 의해 호출되면 console.log() 함수에 대한 실행 컨텍스트가 생성된다.
변수를 let/const 로 선언한 경우
자바스크립트 엔진이 환경 레코드에 식별자를 기록만 해두고 값을 초기화하지는 않는다. (undefined 로 미리 값을 할당하지 않는다.)
때문에, 선언하기 이전에 식별자를 참조하려고 하면 Reference Error 가 발생한다.
일시적 사각지대 (Temporal Dead Zone)
let 이나 const 로 선언해 선언 라인 이전에 식별자를 참조할 수 없게 되는 구역
var 키워드로 변수를 선언하는 경우에는 선언과 동시에 초기화가 이루어 진다.
선언 단계에서는 메모리 공간을 확보한 뒤 메모리 주소에 식별자를 연결하고,
초기화 단계에서는 식별자를 암묵적으로 undefined 값으로 초기화 한다.
변수를 let/const 키워드로 선언하면 선언 단계에서 메모리에 식별자를 연결해두지만,
값은 undefined 로 초기화하지 않는다.
따라서 재할당 전까지는 변수에 아무 값이 담기지 않아서 선언만 했을 때는 값을 읽어 올 수 없다.(TDZ)
2. 함수 호이스팅
자바스크립트에서는 함수를 변수에 담을 수 있다는 특징이 있다.
이를 함수 표현식이라고 한다.
함수 표현식
함수 표현식은 함수를 변수에 담고 있기 때문에 기본적으로 변수 호이스팅과 똑같이 동작하지만 var의 경우에는 차이가 있다.
var 변수에 함수를 담아 선언문 이전에 실행하려고 하면 undefined 가 출력되는게 아니라 Type error 가 출력된다.
let/const 키워드의 함수 표현식은 변수 호이스팅의 경우와 같다. (환경 레코드에 기록된 값이 없어 Reference error 발생)
study() // error
const study = () => {
// ...
}
함수 선언문
var, let/const 가 아닌 그냥 function 으로 함수를 선언하는 방식이다.
함수 선언문은 자바스크립트 엔진이 코드를 스캔할 때 완성된 함수 전체를 한 번에 환경 레코드에 기록해둔다.
코드 상의 어디에서 호출해도 이미 key 역할을 하는 식별자 함수가 그 함수의 value인 함수로 초기화되어 있어 에러가 발생하지 않는다.
이러한 특징 때문에 사용을 지양하기도 한다.
study() // ...
function study() {
// ...
}
// 함수 표현식의 환경 레코드
// 1. var
{ study : undefined }
// 2. let/const
{ study }
// 함수 선언문의 환경 레코드
{ study : f {} }
outerEnvironmentRefernce
- 스코프 체인을 가능하게 하는 것이 outerEnvironmentRefernce 이다. (스코프란 식별자에 대한 유효범위)
- outerEnvironmentRefernce는 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조한다.
- 연결 리스트의 형태를 띄며, 선언 시점의 LexicalEnvironment 를 계속 찾아 올라가다 보면 마지막에는 전역 컨텍스트의 LexicalEnvironment 가 있을 것이다.
- 구조적인 특성상 여러 스코프에서 동일한 식별자를 선언한 경우 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능하다.
var a = 1;
var outer = function() {
var inner = function(){
console.log(a);
var a = 3;
};
inner();
console.log(a);
};
outer();
console.log(a);
호이스팅 결과
var a = 1;
var outer = function() {
var inner;
inner = function(){
var a;
console.log(a);
a = 3;
};
inner();
console.log(a);
};
outer();
console.log(a);
스코프 체인 출력 결과
undefined //inner안에서 a를 발견했지만 값이 없음
1 //outer에서 a발견하지 못함 -> 바깥에서 탐색 -> 전역에서 a발견
1 //전역에서 a발견
https://muyeon95.tistory.com/175
전역 변수와 지역 변수
전역 변수는 전역 스코프에서 선언한 것이고 지역 변수는 함수 내부에서 선언한 변수들이다.
코드의 안정성을 위해 가급적 전역변수 사용을 최소화하고자 노력하는 것이 좋다.
ex) 즉시 실행 함수 활용, 네임 스페이스, 모듈 패턴, 샌드박스 패턴, 모듈관리 도구 AMD, CommonJS, ES6 모듈 등
this
실행 컨텍스트의 thisBinding 에는 this 로 지정된 객체가 저장된다.
실행 컨텍스트가 활성화 당시에 this 가 지정되지 않은 경우 this 에는 전역 객체가 저장된다.
그 밖에 함수를 호출하는 방법에 따라 this 에 저장되는 대상이 다르다.
추후에 보충하도록 하겠다.
정리 및 요약
실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.
실행 컨텍스트는 전역 공간에서 자동으로 생성되는 전역 컨텍스트와 eval 및 함수 실행에 의한 컨텍스트 등이 있다.
실행 컨텍스트 객체는 활성화 되는 시점에 VariableEnvironment, LexicalEnvironment, ThisBinding 의 세가지 정보를 수집한다.
실행 컨텍스트를 생성할 때는 VariableEnviroment와 LexicalEnvironment가 동일한 내용으로 구성되지만 LexicalEnvironment 는 함수 실행 도중에 변경되는 사항이 즉시 반영되는 반면 VariableEnvironment 는 초기 상태를 유지한다.
VariableEnvironment 와 LexicalEnvironment 는 매개변수명, 변수의 식별자, 선언한 함수의 함수명 등을 수집하는 environmentRecord 와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference 로 구성되어 있다.
호이스팅은 코드 해석을 좀 더 수월하게 하기 위해 environmentRecord 의 수집 과정을 추상화한 개념으로, 실행 컨텍스트가 관여하는 코드 집단의 최상단으로 이들을 끌어올린다고 해석하는 것이다.
변수 선언과 값 할당이 동시에 이뤄진 문장은 선언부만을 호이스팅하고, 할당 과정은 원래 자리에 남아있게 되는데, 여기서 함수 선언문과 함수 표현식의 차이가 발생한다.
스코프는 변수의 유효범위를 말한다. outerEnvironmentReference 는 해당 함수가 선언된 위치의 LexicalEnvironment 를 참조한다.
코드 상에서 어떤 변수에 접근하려고 하면 현재 컨텍스트의 LexicalEnvironment를 탐색해 발견되면 그 값을 반환하고, 발견하지 못 할 경우 다시 outerEnvironmentReference 에 담긴 LexicalEnvironment 를 탐색하는 과정을 거친다.
전역 컨텍스트의 LexicalEnvironment 까지 탐색해도 해당 변수를 찾지 못하면 undefined 를 반환한다.
전역 컨텍스트의 LexicalEnvironment 에 담긴 변수를 전역 변수라 하고, 그 밖에 함수에 의해 생성된 실행 컨텍스트의 변수들은 모두 지역변수이다.
안전한 코드 구성을 위해 가급적 전역 변수의 사용은 최소화 하는 것이 좋다.
this에는 실행컨텍스트를 활성화하는 당시에 지정된 this 가 저장된다. 함수를 호출하는 방법에 따라 그 값이 달라지는데, 지정되지 않은 경우에는 전역 객체가 저장된다.
참고링크
https://gyyeom.tistory.com/128
https://velog.io/@yena1025/%EC%8B%A4%ED%96%89%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8
https://www.youtube.com/watch?v=EWfujNzSUmw&list=RDCMUC-mOekGSesms0agFntnQang&index=8