import / export 구분이 없었던 이전 상황
자바스크립트는 <script>
태그를 사용하여 외부의 스크립트 파일을 가져올 수는 있지만, 파일 마다 독립적인 파일 스코프를 갖지 않고 하나의 전역 객체를 공유한다.
예를 들어 math.js 와 app.js 를 <script>
태그에 넣는다고 하자.
math.js를 먼저 로딩하고, app.js를 로딩한다.
<html>
<head> </head>
<body>
<script src="./src/math.js"></script>
<script src="./src/app.js"></script>
</body>
</html>
이때 js 파일안에 각각 같은 변수이름을 사용한다면 가장 뒤에 쓰인 스크립트를 기준으로 변수이름이 적용된다.
// (math.js)
function sum(x, y) {
return x + y;
}
// (app.js)
sum(1, 2)
console.log(sum(1, 2)); // 3
전역 스코프에 함수가 노출되면 생기는 문제점
여기서 문제는 sum이 전역 스코프에 노출되는 것이다.
만약 sum에 1을 새롭게 할당한다면 이제는 sum이라는 함수를 호출할 수 없는 상황이 된다.
즉, 다른 파일에서 같은 변수 이름을 쓰면 충돌한다.
이렇게 스코프 문제가 발생하고, 의존성 관리 문제도 해결되지 않으므로 모듈화를 구현하기 어렵다.
즉시 실행 함수 표현(IIFE, Immediately invoked Function Expression) 은 정의되자마자 즉시 실행되는 JavaScript Function 를 말한다.
(function() {
statements
})()
// IIFE 내부에서 정의된 변수는 외부 범위에서 접근이 불가능하다.
(function() {
var aName = "Mary"
})()
aName // Uncaught ReferenceError: aName is not defined
// IIFE를 변수에 할당하면 IIFE 자체는 저장되지 않고, 함수가 실행된 결과만 저장된다.
var result = (function() {
var name = "Mary"
return name
})()
// 즉시 결과를 생성
result // "Mary"
IIFE는 스코프 문제를 해결했지만 바로 실행한다는 점에서 모듈화의 해결책은 아니다.
이렇게 모듈기능은 반드시 해결해야할 과제였다. 그래서 제안된 것이 바로 AMD 와 CommonJS이다.
CommonJS
CommonJS는 JavaScript를 브라우저에서 뿐만 아니라, 서버 사이드 애플리케이션이나 데스크톱 애플리케이션에서도 사용하려고 조직한 자발적 워킹 그룹이다.
대표적으로 서버 사이드 플랫폼인 Node.js에서 이를 사용한다.
.exports 키워드로 모듈을 만들고 require() 함수로 임포트하는 방식이다.
<script>
태그로 파일을 가져오는 것이 아니라 필요한 함수나 변수를 가져올 수 있다.이렇게 CommonJS는 모듈화의 조건을 충족시키지만 이 방식은 브라우저에서는 필요한 모듈을 모두 내려받을 때까지 아무것도 할 수 없게 된다는 결정적인 단점이 있었다.
AMD
AMD(Asynchronous Nodule Definition)는 비동기로 로딩 되는 환경에서 모듈을 사용하는 것이 목표다.
이 방식은 define 함수 내에 코드를 작성함으로써 스코프(Scope) 분리가 가능하다.
※ 비동기 처리란 특정 코드가 종료되지 않았어도 대기하지 않고 다음 코드를 실행하는 자바스크립트의 특성이다.
define(['./foo.js', './boo.js'], function(foo, boo){
//
})
ES6 모듈
ES6 에서는 export를 이용해 모듈로 만들고 import로 가져온다.
// math.js
export function sum(x, y) {
return x + y;
}
// app.js
import * as math from "./math.js"
console.log(math.sum(1, 2));
// import {sum} from "./math.js"
// -> *sum만 가져오고 싶다면 이렇게 사용할 수도 있다.*
→ import * as name
은 모든 export를 가져오고 name 매개 변수는 모듈 객체의 이름으로, export를 참조하기위한 일종의 네임스페이스로 사용된다.
결론적으로 ES6에서는 클라이언트 사이트 자바스크립트에서도 동작하는 모듈 기능을 추가했다.
*<script>
태그에 type="module" 속성을 추가하면 모듈로 사용할 수 있다.*
<script type="module" src="./src/app.js"></script>
→ 이때는 app.js에서 math를 가져오기 때문에 math.js은 따로 로드하지 않아도 된다.
그러나 아직까지는 모든 브라우저에서 지원하지 않기 때문에 브라우저와 무관하게 사용할 수 있는 모듈이 필요하다. → 그래서 Webpack을 사용한다.