실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓는 객체를 의미한다.
-> 객체란 실세계의 사물이나 개념을 소프트웨어 세계 내 추상화한 것을 의미한다.
JS는 동일한 환경에 있는 정보들을 모은 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경과 순서를 보장할 수 있게 된다.
스택(Stack)이란? 출입구가 하나뿐인 깊은 우물 같은 데이터 구조를 의미하며 비어있는 스택에 순서대로 a, b, c, d를 넣는다고 가정하면 꺼낼때는 d, c, b, a의 순서로 꺼내게 된다.
=> 스택을 사용하는 이유는 스택의 대표적인 특징인 (FILO(선입후출) : First in Last Out)가 순서를 보장해주고, 콜스택 내부에 쌓인 실행 컨텍스트의 정보를 통해 환경을 보장할 수 있다.
(환경은 전역 변수 혹은 함수 내부의 환경이 될 수 있다.)
=> 콜스택(Call Stack)이란 자바스크립트 코드가 실행되며 생성되는 실행 컨텍스트(Execution Context)를 저장하는 자료구조를 의미한다.
하나의 실행 컨텍스트를 구성할 수 있는 방법으로 전역공간과 eval() 함수, 함수 등이 있으며 자동으로 생성되는 전역공간과 eval()함수를 제외하면 실행 컨텍스트를 구성할 수 있는 방법은 함수를 실행하는 것뿐이다.
(ES6에서 블록에 의해서도 새로운 실행 컨텍스트가 실행된다)
// 실행 컨텍스트와 콜스택
var a = 1;
function outer(){
function inner(){
console.log(a);
var a = 5;
}
inner();
console.log(a);
}
outer();
console.log(a);
(1) 콜스택엔 전역 컨텍스트를 제외하곤 다른 컨텍스트가 없기에 전역 컨텍스트와 관련된 코드를 진행한다.
(2) 전역 컨텍스트와 관련된 코드를 진행 중 outer()함수를 호출함으로써 outer에 대한 환경 정보를 수집하여 outer 실행 컨텍스트를 생성한 후 콜스택에 담는다.
콜스택의 맨 위에 outer 실행 컨텍스트가 있기 때문에 전역 컨텍스트와 관련된 코드실행은 일시 중단하고 outer 실행 컨텍스트와 관련된 코드, 즉 outer 함수 내부의 코드들을 순차로 실행한다.
(3) inner 함수의 실행 컨텍스트가 콜스택 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행한다.
(4) inner 함수 내부에 a 변수에 값 5를 할당하고 나서 inner 함수의 실행이 종료되면서 inner 실행 컨텍스트가 콜스택에 제거된다. 제거된 후 아래에 있던 outer 컨텍스트가 콜스택의 맨위에 존재하게 되고 중단했던 outer() 함수를 실행한다.
(5) a변수의 값이 출력되면 outer 함수의 실행이 종료되어 outer 실행 컨텍스트가 콜스택에서 제거되고, 콜스택에는 전역 컨텍스트만 남아 있게 된다.
(6) 실행을 중단했던 전역 컨텍스트를 실행한다. a변수의 값을 출력하고 나면 전역공간에 더는 실행할 코드가 남아 있지 않아 전역 컨텍스트도 제거되어 콜스택에 아무것도 남아있지 않는 상태로 종료된다.
VariableEnvironment와 LexicalEnvironment는 현재 컨텍스트 내 식별자들에 대한 정보 + 외부 환경 정보, 선언 시점의 스냅샷으로, VariableEnvironment는 변경사항이 반영되지 않는 초기 상태를 유지, LexicalEnvironment는 변경사항이 반영된다.
VariableEnvironment와 LexicalEnvironment의 구성은 매개변수명, 변수의 식별자, 선언한 함수의 함수명 등을 수집하는 environmentRecord와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference로 구성된다.
ThisBinding : 식별자가 바라봐야 할 대상 객체
console.log(num);
var num = 10;
// 실행결과 : undefined
// 실제 호이스팅에 의해 다음 코드처럼 작동함
var num; // 호이스팅으로 선언이 최상위로 올라가 있음
console.log(num);
num = 10; // 할당은 원래 자리에 있음
TDZ(Temporal Dead Zone)은 let, const, class로 선언된 변수가 실제로 선언되고 초기화되기 전까지의 코드 영역을 의미한다.
이 구간에서 해당 변수에 접근하려고 하면 'ReferenceError'가 발생한다.
console.log(x); //TDZ 발생 : Reference Error, x가 초기화되기 전까지 'x'에 접근할 수 없다.
let x = 10; // TDZ 끝
console.log(x); // 10
- 코드의 재사용성 : 동일한 코드 블록을 여러 곳에서 호출하여 사용하며 코드의 불필요한 중복을 피하고 유지보수성 증가한다.
- 모듈화 : 프로그램을 더 작은 단위로 나눌 수 있다. 프로그램의 복잡성을 줄이고 코드를 논리적으로 구성한다.
import : export를 통해 내보내는 진 것을 가져다가 사용하는 것을 의미한다.
export : 자신이 만든 모듈의 함수, 객체, 변수를 다른 모듈에서 가져다가 사용할 수 있도록 내보낼 때 사용한다.- 유지보수성 : 코드를 논리적으로 분할하고 구성할 수 있어 이해와 수정이 편리하다.
- 코드의 가독성 : 함수의 이름을 통해 작업 목록을 직관적으로 이해할 수 있으며, 코드를 읽기 쉽고 이해하기 쉽도록 만든다.
- 테스트 용이성 : 동일한 입력에 대해 항상 동익한 출력을 보장하기 때문에 특정 함수의 테스트 케이스 작성에 용이하다.
- 함수 선언문이란 function키워드를 사용해서 이름이 있는 함수를 선언하고 정의한다. 해당 함수는 호이스팅에 의해 스코프 내 어느곳이든 호출이 가능하다. 식별자 뒤에 소괄호를 붙인다.
// 기본틀 function 식별자(){ }
// 예제코드 function gugudan(){ for(let i = 1; i <= 9; i++){ console.log('3 * ${i} = ${3 * i}'); } }
- 함수 표현식이란 함수를 변수에 할당하는 방식으로 function 키워드를 사용해 변수에 할당할 수 있는 식을 의미한다. 호이스팅이 발생하지만 함수가 할당되기 전까지는 호출할 수가 없다.
- 함수 표현식은 함수에 식별자가 있으면 네이밍 함수(naming function), 없으면 익명함수(anonymous function)로 다시 구분한다.
- 함수 표현식은 선언문과 달리 function 키워드 뒤에 오는 식별자로 호출하지 않고, 할당한 변수명으로 호출한다. 그렇지 않으면 ReferenceError : naming is not defined 에러가 발생한다.
//함수표현식 사용 방법 const 변수명 = function(){}; // 익명함수 const 변수명 = function 식별자(){}; // 네이밍 함수
// 예제코드 네이밍 함수 const gugudan = function gugudan(){ for(let i = 1; i <= 9; i++){ console.log('3 * ${i} = ${3 * i}'); } }; // 변수에 할당하기 때문에 ;(세미콜론)을 붙여준다. gugudan(); // 함수 호출
// 예제코드 익명함수 const gugudan = function(){ for(let i = 1; i <= 9; i++){ console.log('3 * ${i} = ${3 * i}'); } }; // 변수에 할당하기 때문에 ;(세미콜론)을 붙여준다. gugudan(); // 함수 호출
// 식별자로 함수를 호출할 경우 에러 발생하는 예제 코드 const gugudan = function naming(){ for(let i = 1; i <= 9; i++){ console.log('3 * ${i} = ${3 * i}'); } }; // 변수에 할당하기 때문에 ;(세미콜론)을 붙여준다. naming(); // 함수 호출
- 화살표 함수란 function키워드를 생략하고 => 기호를 사용하여 함수를 더욱 간결하게 표현하는 방식으로 ()와 return을 생략할 수 있다.
- 익명함수로만 정의할 수 있기 때문에 함수를 호출하려면 정의된 함수를 변수에 할당하는 방법(함수표현식)을 사용해야 한다.
//화살표 함수 표현식 방법 ()=>{};
// 예제코드 화살표 함수 const gugudan = () => { for(let i = 1; i <= 9; i++){ console.log('3 * $ {i} = ${3 * i}'); } }; gugudan();
함수 선언문으로 선언된 함수는 함수 호이스팅이 발생한다. 런타임 이전에 함수 객체가 생성되므로 함수가 정의도기 전에 함수를 호출할 수 있다.
함수 표현식으로 선언된 함수는 변수 호이스팅이 발생한다. 그렇기 때문에 undefined로 초기화가 되며 함수 표현식으로 선언한 함수는 함수가 정의되기 전에 함수를 호출할 수 없다.