[javascript 자바스크립트] 실행 컨텍스트(Execution Context) 란?

resilient

·

2021. 12. 3. 11:59

728x90
반응형

자바스크립트를 사용하다 보면 남이 쓴 코드를 볼 때 '이게 어떻게 되지?' 라는 생각, 혹은 '내가 작성을 하면서도 이게 맞나?' 라는 생각을 많이 할 때가 있습니다. 그럴 때마다 자바스크립트를 확실하게 이해하지 못해서 그렇다고 생각이 들었고, 이번 기회에 자바스크립트를 딥하게 공부해서 정리를 해보려고 합니다.

 

그럼 이번 시간에는 scope, hoisting, this, function 등 대부분의 동작원리를 담고 있는
실행 컨텍스트에 대해 알아보겠습니다.

 

그럼 실행 컨텍스트란 뭘까?

 

콘텍스트는 한국말로 번역하면 문맥입니다. ECMAScript 스펙에 따르면 실행 컨텍스트를 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이라고 정의하고 있습니다.
좀 더 쉽게 말하자면 실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경이라고 말할 수 있겠네요.

 

아래 예제를 보고 어떻게 console이 찍힐지 생각해볼까요? 아마도 nero, hello zero 가 찍힐 겁니다.
(주석에 간단하게 순서를 적어봤습니다.)

 

var name = 'skc'; // (1)변수 선언 (6)변수 대입
function wow(word) { // (2)변수 선언 (3)변수 대입
  console.log(word + ' ' + name); // (11)
}
function say () { // (4)변수 선언 (5)변수 대입
  var name = 'cks'; // (8)
  console.log(name); // (9)
  wow('hello'); // (10)
}
say(); // (7)

 

위 예시를 과정을 이해하려면 lexical scoping을 알아야 합니다.
lexical scoping 이란 scope는 함수를 호출할 때가 아닌 어디서 선언되었는지를 고려한다는 의미입니다.
(스코프(scope)는 범위라는 뜻으로 함수에서 선언된 변수는 해당 함수 안에서만 사용할 수 있어요. 지역변수와 전역 변수를 구분할 때도 스코프(scope)를 기준으로 합니다.)

**이번시간에 lexical scoping을 정리했으니 다음 시간에는 클로저(closure)를 정리해 봐야겠네요.**

 

그럼 다시 돌아와서 위 예제가 어떻게 실행되는지 살펴보겠습니다.

 

처음 코드를 실행하면 모든 것을 포함하는 전역 컨텍스트가 생깁니다. 전역컨텍스트는 모든 것을 관리하는 환경이고, 페이지가 종료될 때까지 유지되죠.
전역 컨텍스트 말고도 함수 컨텍스트 라는게 있습니다. 함수 컨텍스트는 언제 생기냐?  자바스크립트는 함수 스코프(scope)를 따르는데, 함수를 호출할 때마다 함수 컨텍스트가 하나씩 더 생깁니다.

 

 

실행 컨텍스트의 원칙에는 네 가지가 있습니다.

  • 먼저 전역 컨텍스트 하나 생성된 후, 함수 호출 시마다 컨텍스트가 생깁니다.
  • 컨텍스트 생성 시 컨텍스트 안에 변수 객체(arguments, variable), scope chain, this가 생성됩니다.
  • 컨텍스트 생성 후 함수가 실행되는데, 사용되는 변수들은 변수 객체 안에서 값을 찾고, 없다면 스코프 체인을 따라 올라가며 찾게 됩니다.
  • 함수 실행이 마무리되면 해당 컨텍스트는 사라지고, (클로저 제외) 페이지가 종료되면 전역 컨텍스트가 사라지게 됩니다.

 

위의 실행 컨텍스트 원칙에 따라서 위에서 사용했던 예제 코드들 순서대로 정리해보겠습니다.

 

 

전역컨텍스트

전역컨텍스트가 생성된 후 두 번째 원칙에 따라 변수 객체, scopechain, this 가 들어오게 됩니다.

전역컨텍스트는 arguments(함수 인자)가 없고, variable은 해당 스코프의 변수들로 name, wow, say가 있습니다.

 

객체 형식으로 표현해보겠습니다.

 

'전역 컨텍스트': {
  변수객체: {
    arguments: null,
    variable: ['name', 'wow', 'say'],
  },
  scopeChain: ['전역 변수객체'],
  this: window,
}

 

이제 코드를 위에서부터 실행하게 되는데, wow랑 say는 호이스팅 때문에 선언과 동시에 대입이 되고 variable의 name에 'skc'가 대입이 됩니다.

 

variable: [{ name: 'skc' }, { wow: Function }, { say: Function }]
호이스팅(hoisting)이란?

호이스팅이란 변수를 선언하고 초기화했을 때 선언 부분이 최상단으로 끌어올려지는 현상을 의미합니다. (초기화 또는 대입 부분은 그대로 남아있게 됩니다.)
함수 표현식이 아니라 함수 선언식 일 때는 식 자체가 통째로 끌어올려지게 되죠.

예를 들어 아래와 같은 코드를 실행하면 sayWow()가 선언되고 최상단으로 끌어올려지기 때문에 sayWow함수 위에서 sayWow() 함수를 실행했을 때 정상적으로 wow가 찍히는 것이죠.
console.log(skc); // 에러가 아니라 undefined
sayWow(); // 정상적으로 wow
function sayWow() {
  console.log('wow');
}
var zero = 'skc';​

 

함수컨텍스트

 

var name = 'skc'; // (1)변수 선언 (6)변수 대입
function wow(word) { // (2)변수 선언 (3)변수 대입
  console.log(word + ' ' + name); // (11)
}
function say () { // (4)변수 선언 (5)변수 대입
  var name = 'cks'; // (8)
  console.log(name); // (9)
  wow('hello'); // (10)
}
say(); // (7)

 

(7) 번에서 say(); 를 실행하면, 새로운 컨텍스트인 say 함수 컨텍스트가 생깁니다.

물론 전역 컨텍스트는 그대로 있겠죠?
arguments는 없고 variable은 name, scope는 say변수 객체와 상위의 전역 변수 객체이고, this는 따로 설정해준 적이 없으므로 window가 되겠습니다.

'say 함수컨텍스트': {
  변수객체: {
    arguments: null,
    variable: ['name'], // 초기화 후 [{ name: 'cks' }]가 됨
  },
  scopeChain: ['say 변수객체', '전역 변수객체'],
  this: window,
}

 

  • say를 호출한 후 위에서부터 차례대로(8)~(10) 과정을 실행하게 됩니다.
  • variable의 name에 cks를 대입해주고 나서 console.log(name);이 있습니다.
  • name 변수는 say 컨텍스트 안 variable에 name이 cks라고 되어 있으므로 name이 콘솔에 찍히게 됩니다.
  • 그다음엔 wow('hello')가 있는데. say 컨텍스트 안에서 wow 변수를 찾을 수 없습니다! 찾을 수 없다면 scope chain을 따라 올라가 상위 변수 객체에서 찾아야 하기 때문에 전역 변수객체에서 찾게 됩니다.
  • 전역 변수 객체의 variable에 wow라는 함수가 있고 이걸 호출하게 되죠.

 

(10) 번에서 wow함수가 호출되면 wow 함수 컨텍스트도 생기게 됩니다.


arguments는 word='hello'이고 scope chain은 wow 스코프(scope)와 전역 스코프입니다.
어? wow()는 say() 안에 있는데 say scope는 wow의 scope chain이 아닌가요?


여기서 중요한 점은 lexical scoping에 따라 wow함수의 scope chain은 선언 시에 이미 정해져 있습니다.
따라서 say scope는 wow 함수 컨텍스트의 scope chain이 아닙니다.

variable은 없고 this는 window가 되겠죠?

 

'wow 함수컨텍스트': {
  변수객체: {
    arguments: null,
    variable: ['name','word'], 
  },
  scopeChain: ['wow 변수객체', '전역 변수객체'],
  this: window,
}

 

  • wow 함수 안에 console.log(word + ' ' + name);이 있습니다.
    word랑 name 변수는 wow 컨텍스트에서 찾으면 되겠죠?
  • word는 arguments에서 찾을 수 있고, name은 wow 변수 객체에는 값이 없으니, scope chain을 따라 전역 스코프에서 찾으면 됩니다.
  • 전역 변수 객체로 올라가니 variable에 name이 skc라고 되어 있기 때문에  hello cks가 아닌 hello skc가 됩니다.
  • wow 컨텍스트에 따르면 wow 함수는 애초에 say 컨텍스트와 일절 관련이 없습니다. (위의 설명을 참고!)

 

이후, wow 함수가 종료되면 wow 함수 컨텍스트는 사라지고 say 함수도 종료되고 say 컨텍스트도 사라지고 마지막으로 전역 컨텍스트도 사라지게 됩니다.

 

정리 

자 이번 시간에는 실행 콘텍스트(Execution Context) 에 대해서 알아봤는데요,
javascript를 공부하면서 꼭 알아야 하는 개념이라고 생각이 듭니다. 처음 보면 어렵고 무슨 말인지 모르겠지만 예시와 함께 천천히 여러 번 읽다 보면 이해가 가실 거예요.
다음 시간에는 클로저(Closure)에 대해서 정리해 보는 시간을 갖겠습니다!

 

 

 

 

 

Reference : https://www.zerocho.com/

반응형