앞서 알아야할 스택
과 큐
스택
: 후입 선출(저장량 넘치면 에러 발생) 큐
: 선입 선출
실행 컨텍스트: 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
같은 환경의 코드 실행 시 필요한 환경 정보를 모아 컨텍스트를 구성한다.
그 후 콜스택에 쌓고 맨 위의 컨텍스트와 관련된 코드 실행해 전체 코드의 환경, 순서를 보장한다.
실행 컨텍스트 구성 방법
⚠️eval함수
는 문자열 스크립트 코드를 실행하는 함수이다. 하지만 보안위험이 있어 사용해선 안된다.⚠️
console.log('2 + 2'); //'2 + 2'
console.log(eval('2 + 2')); //4
var a = 1; // 전역 컨텍스트
function outer () { // outer 컨텍스트
function inner () { // inner 컨텍스트
console.log(a); // undefined
var a = 3;
console.log(a); // 3
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
아래는 실행 컨텍스트 구성 시 실행 컨텍스트 객체에 저장되는 정보들이다. (js엔진이 활용할 목적)
LexicalEnvironment
의 스냅샷으로, 변경사항은 반영되지 않음.VariableEnvironment
와 같지만 변경사항이 실시간으로 반영됨.실행 컨텍스트 생성 시 VariableEnvironment
에 정보 담고, 복사해 LexicalEnvironment
를 만든다.
이후엔 LexicalEnvironment
를 주로 활용한다.
LexicalEnvironment는 2가지 정보를 수집한다.
environmentRecord
와 outerEnvironmentReference
이다.
environmentRecord에는 현 컨텍스트와 관련된 식별자 정보가 저장된다.
호이스팅: JS엔진은 식별자들을 최상단으로 올려놓고 실제 코드를 실행한다.
(변수 정보 수집 과정 이해를 위한 가상 개념, 실제 동작 방식X)
//원본
function a(x) {
console.log(x)
var x;
console.log(x)
var x = 2;
console.log(x)
}
a(1)
함수 내부 코드보다 인자의 선언/할당이 먼저 이뤄진 것과도 같아 아래의 코드로 바꿨다.
function a() {
var x = 1;
console.log(x)
var x;
console.log(x)
var x = 2;
console.log(x)
}
a()
호이스팅이 이뤄지면 변수는 선언부만 올라가고, 할당부는 제자리에 남는다.
//호이스팅 끝
function a() {
var x;
var x;
var x;
x = 1;
console.log(x)
console.log(x)
x = 2;
console.log(x)
}
a(1)
호이스팅을 알기전엔 원본 코드의 결과가 1
, undefined
, 2
라고 예상할 수 있지만 호이스팅을 알게된 지금은 1
, 1
, 2
라는 결과를 예상할 수 있다.
//원본
function a() {
console.log(b);
var b = 'bbb';
console.log(b);
function b() {}
console.log(b);
}
a();
호이스팅 시 변수명, 함수 선언의 정보가 올라간다. 그럼 아래의 형태가 된다.
//호이스팅 끝
function a() {
var b
function b() {} //(1) var b = function b() {}
console.log(b); //함수b 출력
b = 'bbb';
console.log(b); //'bbb'
console.log(b); //'bbb'
}
a();
함수명으로 선언한 b라는 변수에 함수를 할당한 것과도 같기에, 주석(1)처럼 여길 수도 있다.
function a () {} // 함수 선언문, 함수명이 변수명
var a = function () {} // (익명) 함수 표현식, 변수명이 함수명
var a = function b() {} // 기명 함수 표현식, 변수명 함수명 따로
함수 선언문: 함수 정의부만 있고, 할당 명령은 없다.
(익명) 함수 표현식: 정의한 함수를 변수에 할당한다.
기명 함수 표현식: 함수명을 정의한 함수를 변수에 할당한다.
a함수
선언시 실행되지만 b함수
는 에러가 발생한다.//원본
console.log(sum(1, 2));
console.log(multiply(3, 4));
function sum (a, b) {
return a + b;
}
var mutiply = function(a,b) {
return a * b;
}
위 코드를 봤을 땐 콘솔창에 3
, 12
가 잘 출력될거 같지만 아니다.
//호이스팅 끝
var sum = function sum (a, b) {
return a + b;
}
var mutiply;
console.log(sum(1, 2));
console.log(multiply(3, 4));
mutiply = function(a,b) {
return a * b;
}
위 코드는 호이스팅이 완료된 상태이다.
함수 선언문은 함수 전체가 올라가지만, 함수 표현식은 함수를 변수에 할당했기 때문에 변수 선언부만 올라가고 할당부는 제자리에 남는다. 그래서 3
이 출력되고 mutiply is not a function
이란 에러가 출력된다.
따라서 함수 표현식은 선언 이전에 호출할 수 없어서 실수를 미연에 방지할 수 있다.
스코프: 식별자의 유효범위
A경계 외부에서 선언된 변수는 A경계 내부,외부 모두 접근이 가능하지만, A경계 내부에서 선언한 변수는 A경계 내부에서만 접근이 가능하다.
스코프 체인: outerEnvironmentReference를 통해 식별자의 유효범위를 안에서 밖으로 검색하는 것.
”선언하다”라는 행위가 일어나는 상황은 콜스택 상에서 어떤 실행 컨텍스트가 활성화된 상태뿐이다.
함수를 선언하는 행위도 하나의 코드이며, 모든 코드는 실행 컨텍스트가 활성화 상태일 때 실행된다.
A함수{ B함수{ C함수{}}}
이런식의 함수가 있다하면
C함수의 outerEnvironmentReference
는 B함수의 LexicalEnvironment
를 참조한다.
B함수 LexicalEnvironment
의 outerEnvironmentReference
는 A함수의 LexicalEnvironment
를 참조한다.
outerEnvironmentReference
는 선언된 시점의 LexicalEnvironment
만 참조하기 때문에 가까운 요소부터 차례로 접근해서 스코프 체인 상 먼저 발견된 식별자에만 접근한다.
변수 은닉화: 특정 함수 내부에 a변수를 선언하면 외부에서 선언한 동일한 a변수에는 접근할 수 없는 것.
실행 컨텍스트 thisbinding에는 this로 지정된 객체가 저장된다. 실행 컨텍스트 활성화 시 this가 지정되지 않았다면, this에 전역 객체가 지정된다.