코드 리뷰하다가 문득 궁금해져서 테스트 해본 코드. 다음 코드를 실행했을 때 콘솔 로그의 순서는 어떻게 될까? moduleC 코드 다음에 바로 정답이 있으니 궁금한 사람은 스크롤을 멈춰보세요!
App.js
console.log('App 1'); import { moduleA } from './moduleA.js'; console.log('App 2'); import { moduleB } from './moduleB.js';
moduleA.js
console.log('ModuleA 1'); export const moduleA = '하이'; console.log('ModuleA 2'); import { moduleC } from './moduleC.js';
moduleB.js
console.log('ModuleB 1'); export const moduleB = '음음'; console.log('ModuleB 2');
moduleC.js
console.log('ModuleC 1'); export const moduleC = '그래'; console.log('ModuleC 2');
정답은 아래와 같다. 왜요?
$ node app.js ModuleC 1 ModuleC 2 ModuleA 1 ModuleA 2 ModuleB 1 ModuleB 2 App 1 App 2
참고로 나는 틀렸다. 내가 헷갈린 부분은 다음과 같다.
헷갈린 부분
(1) import 전의 코드가 먼저 실행되는가?
(2) export 후의 코드도 같이 실행되는가?
이에 대해 관련된 Javascript의 특성은 Import Hoisting과 Module Evaluation이다. 요 특성에 대해서 요약을 하자면 다음과 같이 할 수 있겠다.
- import문은 호이스팅이 된다.
- Module은 평가되기 전에 모든 종속 모듈이 먼저 평가되어야 한다.
import문이 호이스팅이 되냐 안 되냐에 대한 이야기가 생각보다 많이 없어서 관련 자료를 많이 찾아봤는데, 어쨌든, import문은 호이스팅이 되는 게 맞다!
이때 내가 헷갈린 것은, import는 최상위에 선언되어야 한다. 라는 부분이었는데, '최상위' 라는 단어가 '코드 상 순서로 맨 위'가 아니라, '스코프의 최상위'임을 알고 나선 명료해졌다. 즉, 당연히 block 스코프, 예를 들어 if문 안에서는 선언할 수 없다. (import()는 가능하지만서도, 이건 다른 개념이니까!
그러므로,, 결국 1번과 2번은 서로 연관이 되어 있다. 모든 종속 모듈이 먼저 평가가 되려면 import문이 호이스팅이 되어 종속 모듈을 먼저 불러올 수 있게끔 해야 하므로.
재밌다...