CoreJavaScript Chapter 2. [execution context]

JUGNMIN LEE·2021년 4월 30일
0

CoreJavaScript

목록 보기
2/7
post-thumbnail

CoreJavaScript

1. 실행 컨텍스트란(execution context) ?

실행 컨텍스트는 간단하게 자바스크립트를 실행하기 위해 필요한 환경들, 예를들어 scope, hoisting, this, function,closer 등을 형상화하고 구분하기 위해 실행 컨텍스트라는 물리적 객체의 형태로 관리하는 것이다.

동일한 위치(스코프)의 코드들을 실행할 때에 필요한 환경 정보들을
컨텍스트로 객체화 해서 콜스택에 쌓아 올렸다가 가장 위에 있는 즉, 가장 마지막에 콜스택에 담긴 컨텍스트와 관련 있는 코드들을 실행하는 식이다.

실행 컨텍스트를 구성하는 방법으로는 전역공간과 eval()함수 그리고 그냥 함수가 있는데 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것 뿐 !!

//(1)
var a = 1;
function outer() {
  function inner() {
    console.log(a) // undefined
    var a = 3;
  }
  inner(); //(2)
  console.log(a); //1
}
outer(); //(3)
console.log(a);

위의 코드를 보면서 실행컨텍스트가 어떻게 생기는지 확인해보자.
먼저 (1) 부분에서 전역컨텍스트가 생성되어 콜스택에 담긴다, 전역 컨텍스트의 경우 자바스크립트가 처음 실행되면 무조건 콜스택에 담기기 때문에 관여할 수가 없다

그 다음 담긴 전역컨텍스트와 관련된 코드가 실행되다가 (3)에서 함수 호출을 만나면 전역컨텍스트 실행을 멈추고 outer함수라는 컨텍스트가 콜스택에 담긴다 그 다음 outer를 실행하다가 (2)를 만나게 되면 이 부분에서 outer 컨텍스트가 실행을 멈추고 다시 inner 컨텍스트를 만나서 콜스택에 담긴다 그 뒤로는 다른 컨텍스트를 만들 일이 없으니 inner 컨텍스트 부터 하나 씩 코드가 실행이 된다.

해당 컨텍스트와 관련된 코드들을 해결하면 하나씩 컨텍스트가 지워지는 식 !!

2. 실행 컨텍스트에 담기는 정보들

실행컨텍스트에는 다음과 같은 정보들이 담긴다

VariableEnvironment : 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경정보가 담기며 변경 사항은 반영되지 않는다.
LexicalEnvironment : 처음에는 VariableEnvironment와 같지만(Lexical로 복사가 된다) 변경 사항이 실시간으로 반영이 된다.
ThisBinding : this 식별자가 바라봐야 할 객체의 대상

VariableEnvironment, LexicalEnvironment의 내부에는 동일하게
environmentRecord/outer-EnvironmentReference가 구성되어 있다
이 부분은 아래에 설명을 넣도록 하겠다.

this의 경우 추가로 더 집중적이게 알아봐야할 부분이 많기에 요번엔 넘기고 VariableEnvironment와 LexicalEnvironment만 알아보자

(위의 단어들이 길기에 아래의 글에선 간단하게 ve, le로 부르도록 하겠습니다)

3. VariableEnvironment

일단 ve에 담기는 내용은 le와 같지만 최초 실행 시의 스냅샷을 유지한다는 의미가 있다 이게 무슨말이냐면 실행 컨텍스트가 실행 될때에 ve에 먼저 정보들을 담고 그걸 le로 복사하는 식 ! 즉? ve가 원본이 된다 이런 느낌으로 알면 이해가 빠르다

복사가 되면 ve는 냅두고 주로 le를 사용하게 된다

그렇기에 일단 ve는 원본이며 최초 스냅샷을 유지하고 le로 복사해주는 것만 기억하고 le를 통해 나머지를 설명해보겠다.

4. LexicalEnvironment

일단 le의 경우에는 ve가 최초의 스냅샷으로 원본의 느낌이 있다면
이 녀석은 실제 활용(?)되고 값이 바뀌면 변경이 되는 녀석이다 !

구성으로는 아래와 같이 두가지가 있다. (ve도 포함)
environmentRecord/outer-EnvironmentReference

이 두녀석을 통해 알아가보자.
(마찬가지로 이 두녀석도 편의상을 위해 해당 글에서만 er, oer로 부르겠습니다)

4-1 environmentRecord

er같은 경우 현재 컨텍스트와 관련된 코드의 식별자 정보들이 담기게 된다.
예를들어 함수에 지정된 매개변수나 식별자 혹은 그 함수 자체 또는 선언된 변수들을 의미한다.

그래서 해당 컨텍스트 내부를 처음부터 쭉 훑어서 순서대로 정보들을 수집하고 수집이 다 됬다고해도 아직 실행 컨텍스트가 관여할 코드들 즉 실행될 코드들은 아직 실행되기 전의 상태이다 대신에 자바스크립트 엔진은 이미 수집된 해당 컨텍스트에 속한 환경들의 정보는 모두 알고 있는 셈 ! !

여기서 호이스팅에 대한 개념이 나오게 되는데 호이스팅이란 변수 정보들을 수집하는 과정에서 이해하기 쉽도록 나온 가상의 개념이다.

스코프안에 있는 변수나 함수들을 스코프 최상위로 끌어 올리는 것

아래의 코드를 보고 확인하자

// 매개변수와 변수에 대한 호이스팅 과정
// (1)
function a (x){
  console.log(x);
  var x;
  console.log(x);
  var x = 2;
  console.log(x);
}
a(1);

//(2)
function a (x){
  var x;
  var x;
  var x;
  
  x = 1;
  console.log(x);  
  console.log(x);
  x = 2;
  console.log(x);
}
a(1);

//함수 선언의 호이스팅 과정
//(3)
function a () {
  console.log(b);
  var b = 'bbb';
  console.log(b);
  function b () {}
  console.log(b);
}
a();

//(4)
function a() {
  var b;
  function b () {}
  console.log(b);
  b = 'bbb';
  console.log(b);
  console.log(b);
}
a();

위 코드들은 매개변수와 변수설정 혹은 함수선언에 관해서 호이스팅 과정들이다

(1) 상태에서 (2) 상태로 호이스팅 되었고
(3) 상태에서 (4) 상태로 호이스팅 되었다

er같은 경우는 변수에 어떤 값이 할당되는지는 관심이 없고 무조건 어떤 식별자들이 있는지 관심이 있기 때문에 변수명만 끌어올리고 할당 과정은 그자리에 남겨둔다 선언부와 할당부를 나누어 선언부만 끌어올리는 변수와는 다르게 함수의 경웨는 함수 전체를 끌어올린다 그렇기에 위와 같은 형태가 되는 것이다
(호이스팅은 이해를 위한 가상의 개념으로 실제 저렇고 코드를 작성하지 않습니다)

함수선언문 함수표현식

함수를 정의하는 방식은 세가지가 있다.

아래의 코드를 확인하자

function a(){} // 함수 선언문 방식, 함수명 a가 즉 변수명
a();

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

var c = function d(){} // 기명 함수표현식 변수명은 c 함수명은 d
c(); // 실행 ok
d(); // 에러 출력 !!

여기서 주의해야할 것은 기명 함수표현식에서 함수명은 오직 함수 내부에서만 호출이 가능하다 그래서 예전엔 익명 함수표현식 보다 디버깅시에 장점들이 있었지만 이제는 익명 함수표현식이 똑같은 기능을 해줘 많이 쓰이고 있다

그러면 함수 선언문과 함수 표현식의 호이스팅은 무엇이 다를까 ?
아래의 코드를 보자

//(1)
console.log(sum(1, 2));
console.log(multiply(3, 4));

function sum (a, b){ // 함수 선언문
  return a+b;
}

var multiply = function(a, b){ // 함수 표현식
  return a*b;
}

//(2)
var sum = function sum(a, b){
  return a+b;
};
var multiply;
console.log(sum(1, 2));
console.log(multiply(3, 4));

multiply = function(a, b){
  return a*b;
};

(1)에서 (2)로 호이스팅 됬으며
함수 선언문은 함수 전체를 호이스팅 하지만 함수 표현식은 함수 선언만 호이스팅하고 할당은 아래에 냅둔다(변수처럼)

그래서 이러한 문제로 함수 선언문을 자주 사용하다보면 코드가 길어질 수록 중복된 이름으로 함수 선언문을 다시 작성시에 기존의 함수는 새로 생긴 함수에 의해 덮어씌워지고 그로인해 기존의 잘 실행됬던 코드들이 에러를 뿜어내고 그 에러들은 코드가 길어졌으니 유지보수와 가독성 또한 어렵게 된다.

그렇기에 함수는 전역공간에 선언하거나 동명의 함수명을 중복으로 사용해서는 안되며 전역공간에 동명의 함수가 여럿 존재하는 상황이라 하더라도 모든 함수가 함수 표현식으로 정의되어 있다면 그러한 이슈들을 막을 수 있다.

4-2 outer-EnvironmentReference

oer를 설명할때 필수로 나와야하는 것은 스코프와 스코프 체인이다.

스코프는 코드가 적용되는 유효 범위를 의미하며 function scope의 경우에는 함수 내부에 선언된 변수에만 지역변수로 한정 짓고 block scope의 경우 함수뿐 아닌 if나 for문등에서도 각 변수의 선언이 지역변수로 한정을 짓는다.

스코프 체인의 경우에는 식별자의 유효범위를 안에서부터 바깥으로차례대로 검색해나가는 것을 스코프 체인이라 한다

이러한 기능들을 사용하게 해주는 것이 le안에 있는 oer이란 녀석이다.

아래의 코드를 확인하자.

var a = 1;
var outer = function(){
  var inner = function(){
    console.log(a);
    var a = 3;
  };
  inner();
  console.log(a);
};
outer();
console.log(a);

스코프 체인의 경우 가장 먼저 발견된 식별자에 접근 가능하게 된다 그렇기에 가장 가까운 요소부터 차례대로 탐색해서 접근하고 만약 있다면 상위에 있는 식별자에게는 접근이 불가능하다.

그렇기에 위의 코드에선 inner 함수 안에 있는 console.log(a)의 경우에는 식별자 a에 접근하려 할 때에 현재 활성화 상태인 inner 컨텍스트의 er에서 a를 검색했고 아직 할당된 값이 없으니 undefined를 출력하게 된다.

그래서 inner 함수 내부에서 선언한 변수 a를 찾았기 때문에 전역 공간에서 설정한 a의 변수에는 접근할 수 없는 것을 변수 은닉화 라고 한다.


출처
모든 내용은 코어자바스크립트 공부를 하며 책 내용을 발췌해 이해한 내용들만 추려 적은 내용입니다 해당 코드들은 책 내용의 코드의 값들을 변경하거나 이해를 위해 그대로 가지고 왔습니다.

profile
Frontend Developer

0개의 댓글