[JavaScript] 모듈 시스템

모듈이란 무엇인가?

모듈은 독립형 파일이며, 내부에 클래스, 함수, 변수 등 특정한 기능을 수행하는 코드 조각들을 포함합니다. 모듈은 자체 스코프를 가지므로, 파일 내에서 선언한 변수나 함수는 기본적으로 외부에서 접근할 수 없습니다. 외부에서 해당 기능을 사용하려면 export 지시어를 사용해 공개하고, 다른 모듈에서는 import 지시어로 가져와야 합니다.

// sayHi.js
export function sayHi(user) {
  return `Hello, ${user}!`;
}
// main.js
import { sayHi } from './sayHi.js';

console.log(sayHi('John')); // Hello, John!

모듈의 특징

엄격 모드 자동 적용

JavaScript 모듈은 엄격 모드 ("use strict")로 캡슐화되어 있습니다. 즉, 모듈 내에서 실행되는 코드는 자동으로 엄격 모드 규칙을 준수하며, 잘못된 코딩 방지 및 코드 최적화가 보장됩니다. 선언되지 않은 변수에 값을 할당하거나 암시적 전역 변수를 사용하는 것과 같은 오류를 엄격 모드에서 허용되지 않으며, 오류가 발생하면 ReferenceError가 즉시 발생합니다.

// 다음 코드는 모듈 내에서 실행되면 ReferenceError를 발생시킵니다.
a = 5; // Error: a is not defined

모듈 레벨 스코프

모듈은 독립된 스코프를 가지므로, 모듈 내부에서 선언된 변수나 함수는 다른 모듈과 충돌하지 않습니다. 필요한 경우 export를 통해 외부에 공개할 수 있습니다.

// user.js
const user = "John"; // 모듈 수준 범위에 비공개
export default user;

// main.js
import user from './user.js';
console.log(user); // John

한 번만 평가

동일한 모듈을 여러 모듈에서 여러 번 가져온 경우에도 모듈의 코드는 처음 가져올 때 한 번만 평가되고 실행됩니다. 그 결과로 생성된 객체나 상태는 모듈을 가져오는 모든 곳에 공유됩니다.

// admin.js
export let admin = { name: "John" };

// 1.js
import { admin } from './admin.js';
admin.name = "Pete";

// 2.js
import { admin } from './admin.js';
console.log(admin.name); // Pete

전역 객체 오염 없이 모듈 간 기능 공유

모듈은 전역 스코프를 오염시키지 않습니다. 모듈 내부에 선언된 변수는 기본적으로 외부에서 접근할 수 없으므로, 서로 다른 모듈 간에 독립적으로 코드를 작성할 수 있습니다.

import.meta

모듈 내에서는 import.meta 객체를 통해 현재 모듈에 관한 메타 정보를 얻을 수 있습니다. 예를 들어, 브라우저 환경에서는 현재 모듈의 URL 정보를 확인할 수 있습니다.

// example.js
console.log(import.meta.url);

모듈 스크립트의 지연 실행

모듈 스크립트(<script type="module">)는 항상 지연 실행됩니다. 이는 HTML 문서가 모두 파싱된 후에 모듈 스크립트가 실행됨을 의미합니다. 이러한 지연된 실행을 통해 모듈 스크립트가 DOM에 액세스할 때 HTML 문서가 완전히 로드되고 구문 분석되어 필요한 요소가 스크립트가 실행될 때 사용할 수 있도록 보장합니다. 결과적으로 초기 구문 분석을 차단하지 않고 DOM 콘텐츠에 의존하는 스크립트의 실행이 가능하므로, 웹 페이지 로드 성능이 향상됩니다.

<!-- index.html -->
<!doctype html>
<html>
  <head>
    // module이 아니면 버튼을 찾을 수 없습니다.
    <script type="module">
      // 이 모듈은 HTML 문서가 모두 파싱된 후 실행됩니다.
      const btn = document.getElementById("button");
      console.log(btn); // 정상적으로 버튼 요소를 찾을 수 있음
    </script>
  </head>
  <body>
    <button id="button">Click me</button>
  </body>
</html>