[코어 자바스크립트] 02_실행 컨텍스트

Mooongs·2022년 5월 15일
0

코어자바스크립트

목록 보기
2/8
post-thumbnail

1. 실행 컨텍스트

1-1. 스택과 큐


💡 스택: 출입구가 하나뿐인 깊은 우물 같은 데이터 구조
- a,b,c,d 순서로 저장했다면 꺼낼 때는 d,c,b,a순

💡 큐: 양쪽이 모두 열려있는 파이프 같은 데이터 구조
- a,b,c,d 순서로 저장했다면 꺼낼 때도 a,b,c,d순

1-2. 실행 컨텍스트

실행할 코드에 제공할 환경 정보들을 모아놓은 객체

다음과 같은 방식으로 실행 컨텍스트가 구성된다.

  • 전역 공간 → 자동으로 실행
  • eval() 함수 → 임의의 문자열을 받아 자바스크립트 코드로 실행 / 사용 지양
  • 함수 → 가장 흔한 방식
  • 블록 → ES6부터 지원
// ------------------- (1) 
var a = 1;
function outer() {
  function inner() {
    console.log(a);
    var a = 3;
  }
  inner(); // -------- (2)
  console.log(a);
}
outer(); // ---------- (3)
console.log(a);

👉 실행순서 ('스택'의 개념)
(1) 전역 컨텍스트가 콜 스택에 담긴다
(3)에서 outer 함수가 호출되면 outer 실행 컨텍스트가 콜 스택의 가장 위에 담긴다
(2)에서 inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담긴다

즉, 전역 컨텍스트 → outer 실행 컨텍스트 → inner 실행 컨텍스트 순으로 쌓이고, inner 실행 컨텍스트 → outer 실행 컨텍스트 → 전역 컨텍스트 순으로 실행된다. 한 실행 컨텍스트가 실행될 때 그 밑의 컨텍스트의 실행은 일시중단되고, 실행이 끝나면 그 실행 컨텍스트는 콜 스택에서 제거된다.

2. VariableEnvironment / LexicalEnvironment

2-1. 개념정리

💡 VariableEnvironment: 실행 시의 최초 스냅샷을 담은 내용
💡 LexicalEnvironment: 위의 내용을 그대로 복사한 내용으로, 코드 진행에 따라 변경된다
→ 이 둘은 각각 environmentRecord(현재 컨텍스트 내의 식별자들에 대한 정보)와 outerEnvironmentReference(외부 환경 정보)를 수집한다

2-2. EnvironmentRecord와 호이스팅

💡 EnvironmentReord: 현재 컨텍스트와 관련된 코드의 식별자 정보들을 저장
- ex) 함수의 매개변수 식별자, 함수 자체, var로 선언된 변수의 식별자

💡 호이스팅(중요!!)

자바스크립트 엔진이 식별자들을 최상단으로 끌어올려놓은 다음 실제 코드를 실행한다고 가정하는 가상의 개념

(1) 매개변수와 변수에 대한 호이스팅

environmentRecord는 현재 실행될 컨텍스트에 어떤 식별자들이 있는지에만 관심이 있고, 각 식별자에 어떤 값이 할당될 것인지는 관심이 없다. 따라서 변수 "선언"부분만 최상단으로 올리게 된다.

👉 원본 코드

function a (x) { // 수집 대상 1 (매개 변수)
  console.log(x); // (1)
  var x; // ------- 수집 대상 2 (변수 선언)
  console.log(x); // (2)
  var x = 2; // --- 수집 대상 3 (변수 선언)
  console.log(x); // (3)
}
a(1);

👉 호이스팅을 마친 상태의 코드

function a () {
  var x; // -------- 수집 대상 1(매개 변수)의 변수 선언 부분
  var x; // -------- 수집 대상 2의 변수 선언 부분
  var x; // -------- 수집 대상 3의 변수 선언 부분
  x = 1; // -------- 수집 대상 1의 할당 부분
  console.log(x); // (1) 1출력
  console.log(x); // (2) 1출력
  x = 2; // -------- 수집 대상 3의 할당 부분
  console.log(x); // (3) 2출력
}

a();

(2) 함수 선언의 호이스팅

변수는 위처럼 선언부와 할당부를 나누어 선언부만 끌어올리지만, 함수 선언은 "함수 전체"를 끌어올린다.

👉 원본 코드

function a() {
  console.log(b); // (1)
  var b = 'bbb'; // 수집 대상 1 (변수 선언)
  console.log(b); // (2)
  function b() {} // 수집 대상 2 (함수 선언)
  console.log(b); // (3)
}

a();

👉 호이스팅을 마친 상태의 코드

function a() {
  var b;  // -------  수집 대상 1 (변수 선언)
  function b() {}  // ------ 수집 대상 2 (함수 선언)의 전체
  // var b = function b() {}  // 함수 선언문을 함수 표현식으로 바꾼 코드
  
  console.log(b);  // ------ (1) 함수 b 출력
  b = 'bbb';  // ------- 수집 대상 1의 할당 부분
  console.log(b);  // ------ (2) 'bbb' 출력
  console.log(b);  // ------ (3) 'bbb' 출력
}

a();

2-3. 함수 선언문 / 함수 표현식

💡 함수 선언문

정의부만 존재하고 별도의 할당 명령이 없는 것

function a() {/* ... */}
a(); // 함수명 a가 곧 변수명

❗ 주의할 점
함수 선언문이 코드 상단에 선언되어 있는 상태에서 동일한 이름의 함수 선언문이 코드 하단에 중복해서 선언 될 경우, 호이스팅 과정을 통해 두 함수 선언문이 모두 상단으로 끌어올려지고 가장 마지막의 함수가 코드 전체에 영향을 미치게 된다.

따라서 함수 선언문보다 변수의 선언부만 끌어올리는 함수 표현식이 상대적으로 더 안전하다. (가장 좋은 방법은 함수를 지역변수로 만드는 것!)

💡 함수 표현식

정의한 함수를 별도의 변수에 할당하는 것

var b = function () {/* ... */}
b(); // 익명 함수 표현식. 변수명 b가 곧 함수명

var c = function d () {/* ... */} // 기명 함수 표현식
c(); // 실행 OK
d(); // 에러! 외부에는 함수명으로 함수를 호출할 수 없다

3. 스코프

3-1. 스코프 체인

💡 스코프(Scope) : 식별자에 대한 유효범위

  • ES5까지는 전역공간을 제외하면 "함수"에 의해서만 스코프가 생성
  • ES6부터는 블록 추가

💡 스코프 체인(Scope Chain) : 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것

  • 현재 스코프에 선언된 식별자가 없으면 상위 스코프로 이동하여 검색
  • 여러 스코프에서 동일한 식별자가 선언된 경우에는 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근이 가능하다.
  • 변수 은닉화(variable shadowing) : 상위 스코프에 선언되어 있어도 현재 스코프에 이미 선언된 경우에는, 값이 할당되어 있지 않다고 하더라도 "현재 스코프의 변수"를 우선으로 함

💡 스코프 체인 확인 예시 - 크롬

3-2. 전역변수 / 지역변수

전역변수 : 전역 공간에서 선언한 변수
지역변수 : 함수 내부에서 선언한 변수

profile
#FE개발자🐣 #새로운건 #짜릿해

0개의 댓글