게시글

강좌63 - JavaScript - 한 달 전 등록 / 14일 전 수정

ES2015 이후의 실행 컨텍스트

제가 자바스크립트에서 가장 중요하게 생각하는 것들(실행 컨텍스트, 이벤트 루프, 프로토타입) 중 하나인 실행 컨텍스트 2편입니다. 실행 컨텍스트와 이벤트 루프 분석만 잘 할 줄 알아도 코드를 실행하지 않고도 모든 코드의 실행 순서와 결괏값을 파악할 수 있다고 했죠. 저는 항상 저만의 방식으로 정리하고 있었는데 간만에 또 공유해봅니다.

*주의* 공식 스펙에 적힌 내용과는 좀 다릅니다. 하지만 이렇게 분석해도 99% 정확한 결과가 나옵니다. 나머지 1% 경우를 발견하면 제보해주세요.

안녕하세요. 예전 실행 컨텍스트 글에서 변수 스코프, this, arguments 등을 한 번에 설명하는 것을 보여드렸는데요. 블록 스코프인 let과 const까지 꼈을 때는 어떻게 이해하면 되냐는 질문이 많았습니다. 예전 글은 let과 const에 관한 내용이 없고 var에만 해당했습니다. 그래도 이 글을 읽기 전에 예전 글을 먼저 읽고 오셔야 수월하게 이 글을 읽을 수 있을실 겁니다.

블록 스코프

let과 const가 추가되었다고 많이 달라진 것은 아니고요. 이전에 이해하신 것에서 블록 스코프를 하나 더 추가하면 됩니다. 다음 코드를 한 번 볼까요.

let name = 'zero';
let age = 28;
const wow = (word) => {
  let name = 'nero';
  if (true) { // (2)
    let name = 'hello';
    console.log(age);
  }
  console.log(word + ' ' + name); // (3)
}
wow('hi'); // (1)

실행 컨텍스트를 객체 형식으로 표현하자면 다음과 같습니다.

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

전역 변수 객체는 var때와 같습니다.

이제 wow 함수가 호출되는 상황을 보죠. 주석 (1)번 상황입니다. 함수를 호출했으니 새로운 컨텍스트가 생기는 것도 같습니다.

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

블록 스코프에서는 분석이 조금 달라집니다. 주석 (2) 부분이 실행될 때의 상황입니다. if 문은 블록 컨텍스트를 가지므로 wow 컨텍스트 아래에 블록 컨텍스트가 하나 더 생깁니다. 블록은 { } 라고 생각하시면 됩니다. while, if , for, function 등에서 볼 수 있는 { }가 맞습니다. 객체 리터럴의 { }는 아니고요. 

'wow 컨텍스트': {
  변수객체: {
    arguments: ['hi'],
    variable: ['name': 'nero'],
  },
  scopeChain: ['전역 변수객체', 'wow 변수객체'],
  this: window,
}
'if 블록 컨텍스트': {
   변수객체: {
    variable: ['name': 'hello'],
  },
  scopeChain: ['전역 변수객체', 'wow 변수객체', 'if 블록 변수객체'],
}

블록 컨텍스트에서는 variable과 scopeChain만 있다고 보면 됩니다. arguments는 함수가 아니라서 없고, this는 상위 this를 따라가므로 필요 없습니다.

if 문이 끝나는 순간 블록 컨텍스트는 사라집니다. 따라서 if 문 안에서 name에 접근하면 hello가 되고, if문 바깥에서 name에 접근하면 nero가 됩니다. if 문 안에서 age에 접근하면 scopeChain을 따라 거슬러올라가 전역 변수객체에서 age를 찾아냅니다.

정리하자면 let, const의 도입때문에 실행 컨텍스트 분석이 달라졌다기보다는 블록 스코프의 도입 때문에 달라졌다고 보시면 됩니다. 블록 스코프가 생길 때마다 컨텍스트를 하나 더 만들어두시면 됩니다. 컨텍스트는 블록이 끝나면 사라집니다. 함수 컨텍스트도 { }를 가지고 있으므로 블록 컨텍스트의 일종입니다.

참고로 그냥 { }를 써도 블록이 됩니다. 따라서 이것도 블록 컨텍스트를 만들어두셔야 합니다.

let hello = '1';
{
  let hello = '2';
  console.log(hello);
}
console.log(hello);

for문 분석

for문에서의 컨텍스트도 많이 궁금해하시는 것 같습니다.

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  });
}

다음 결과는 0, 1, 2이지만 var을 쓰면 완전히 달라집니다.

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  });
}

3, 3, 3이 나옵니다. 결괏값이 확연히 차이나는 이유는 역시나 스코프 때문입니다.

var의 경우에는 컨텍스트 분석이 다음과 같이 됩니다. 변수 i가 전역컨텍스트에 생성되기 때문이죠. 일단 i가 3이 된 뒤에 setTimeout이 세 번 호출되는 건 알고 계셔야 합니다.

'전역 컨텍스트': {
  변수객체: {
    arguments: null,
    variable: ['i': 3],
  },
  scopeChain: ['전역 변수객체'],
  this: window,
}
'setTimeout 컨텍스트': {
  scopeChain: ['전역 변수객체', 'setTimeout 변수객체']
}
'setTimeout 컨텍스트': { // 앞에 setTimeout 컨텍스트가 사라진 후 생성됨
  scopeChain: ['전역 변수객체', 'setTimeout 변수객체']
}
'setTimeout 컨텍스트': { // 앞에 setTimeout 컨텍스트가 사라진 후 생성됨
  scopeChain: ['전역 변수객체', 'setTimeout 변수객체']
}

setTimeout 컨텍스트는 편의상 scopeChain만 표시했습니다. 따라서 setTimeout 컨텍스트에서 i를 찾으면 i는 3이 될 수밖에 없습니다.

let의 경우는 다음과 같이 생성됩니다.

'전역 컨텍스트': {
  변수객체: {
    arguments: null,
    variable: null,
  },
  scopeChain: ['전역 변수객체'],
  this: window,
}
'for i = 0 컨텍스트': {
  variable: [i: 0],
  scopeChain: ['전역 변수객체', 'for i = 0 변수객체']
}
'for i = 1 컨텍스트': {
  variable: [i: 1],
  scopeChain: ['전역 변수객체', 'for i = 1 변수객체']
}
'for i = 2 컨텍스트': {
  variable: [i: 2],
  scopeChain: ['전역 변수객체', 'for i = 2 변수객체']
}
'setTimeout 컨텍스트': {
  scopeChain: ['전역 변수객체', 'for i = 0 변수객체', 'setTimeout 변수객체']
}
'setTimeout 컨텍스트': {
  scopeChain: ['전역 변수객체', 'for i = 1 변수객체', 'setTimeout 변수객체']
}
'setTimeout 컨텍스트': {
  scopeChain: ['전역 변수객체', 'for i = 2 변수객체', 'setTimeout 변수객체']
}

전역 컨텍스트에는 아무런 변수가 할당되지 않고, for문을 돌 때마다 컨텍스트가 하나씩 생성된다고 보면 됩니다. 그 안에서 다시 setTimeout 컨텍스트가 생성되므로 setTimeout 안에서 i에 접근하면 각각 0, 1, 2가 나옵니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.

댓글

1개의 댓글이 있습니다.
14일 전
갓.....