August 14, 20226 minutes
안녕하세요?
오늘은 ES6의 모듈(module)에 대해 알아보겠습니다.
모듈은 자바스크립트 프로그래밍에 있어 굉장히 중요한 역할을 하는데요.
코드를 분할하여 좀 더 쉬운 관리가 가능하게 하고, 확장성에 용이합니다.
그러면 이 모듈을 이용해서 변수, 함수, 클래스를 import나 export를 어떻게 하는지 알아보겠습니다.
참고로 ES6의 모듈은 엄격 모드(strict mode)에서만 적용됩니다.
즉, 모듈에서 선언된 변수나 함수가 자동으로 전역 스코프에 적용되지 않는다는 점입니다.
일단 message.js라는 파일이 아래와 같이 있다고 합시다.
export let message = 'ES6 Modules';message.js 파일은 ES6에서 보면 message라는 변수를 가지고 있는 모듈입니다.
그리고 export 명령어를 통해 message라는 변수를 다른 모듈에 노출시키고 있습니다.
즉, export로 변수나 함수를 외부에 노출하여 외부 모듈에서 사용하라고 하는 겁니다.
그럼, 이 모듈을 받아서 코드를 확장하는 다른 모듈을 만들어 볼까요?
아래와 같이 app.js 파일을 만들어 보겠습니다.
import { message } from './message.js';
const hello = 'Hello '+ message;
console.log(hello);위 코드를 보시면 message.js 모듈이 export한 message 변수를 app.js에서 import하여 사용하고 있습니다.
간단한 모듈 사용 로직을 만들었으니, 웹 페이지에 적용해 볼까요?
다음과 같은 HTML 파일을 만듭시다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ES6 Modules</title>
</head>
<body>
<script type="module" src="./app.js"></script>
</body>
</html>위 HTML 파일을 보시면 app.js파일을 불러올 때 아예 type을 module라고 지정했습니다.
ES6 기능인 거죠.
이제 export에 대해 좀 더 자세히 살펴보겠습니다.
우리가 한 모듈에서 변수나, 함수 또는 클래스를 다른 모듈에서 쓰이게끔 하려면 export 키워드를 통해 외부 노출을 해줘야 합니다.
익스포트(export)하는 방식은 아래와 같은 형식이 쓰입니다.
// log.js
export let message = 'Hi';
export function getMessage() {
return message;
}
export function setMessage(msg) {
message = msg;
}
export class Logger {
}log.js 모듈에서 export 하는 방식은 위와 같이 변수, 함수, 클래스 어떤 것이든 가능합니다.
대신에 export 하려면 함수나 클래스의 이름이 꼭 있어야 합니다.
즉, 익명 함수나 익명 클래스는 export가 안 됩니다.
그리고 export는 나중에 한꺼번에 가능합니다.
위 코드에서 각각 export 했지만 아래 코드에서는 한꺼번에 모아서 export 했습니다.
// log.js
let message = 'Hi';
function getMessage() {
return message;
}
function setMessage(msg) {
message = msg;
}
class Logger {
}
export message, getMessage, setMessage;그리고 위 코드에서 보면 제가 일부로 Logger 클래스를 exort 안 했습니다.
그러면 log.js 모듈의 Logger 클래스는 외부 모듈에서 사용할 수 없다는 뜻입니다.
우리가 한 모듈에서 export했으면 이제, 다른 모듈에서 export된 모듈의 변수, 함수, 클래스를 import하여 사용할 수 있습니다.
import { what, ever } from './other_module.js';임포트(import)하려면 괄호 ‘{ }’ 안에 해당 변수나, 함수, 클래스 이름을 나열하면 됩니다.
그러면 export 한 모듈에서의 원래 변수나, 함수, 클래스가 import 한 모듈과 바인딩이 되는 겁니다.
바인딩이 됐다는 의미는 import 한 모듈에서 import 된 변수, 함수, 클래스를 수정할 수 없고, 또 이름이 중복되면 안 된다는 뜻입니다.
예를 들어 볼까요?
// greeting.js
export let message = 'Hi';
export function setMessage(msg) {
message = msg;
}
// app.js
import {message, setMessage } from './greeting.js';
console.log(message); // 'Hi'
setMessage('Hello');
console.log(message); // 'Hello'
message = 'Hallo'; // error
위 코드에서 greeting.js 모듈에 있는 message란 변수를 마지막 줄 코드에서 app.js 파일에서 강제 할당하고 있는데요.
이렇게 하면 에러가 발생합니다. 모듈 간 변수가 바인딩됐기 때문에 직접 수정할 수 없다는 뜻입니다.
쉽게 이해하시려면 모듈에서 import한 변수나, 함수, 클래스가 const 지정자로 선언됐다고 이해하시면 편할 겁니다.
개별 import는 아래와 같이 한 개의 변수만 export하고 다시 import하는 것을 뜻합니다.
// foo.js
export foo = 10;
// app.js
import { foo } from './foo.js';
console.log(foo); // 10;
foo = 20; // throws an error
foo.js 파일에서 foo라는 변수를 export 했고, 그다음 app.js 모듈에서 그걸 import하고 사용했습니다.
개별 import 방식인데요.
그리고 코드 마지막 줄처럼 import된 foo 변수에는 직접 값을 할당할 수 없습니다.
foo 변수가 const로 선언되었다고 생각하시면 에러가 나는 이유를 쉽게 납득하실 수 있을 겁니다.
아래와 같이 cal.js파일이 있고 cal.js 파일에는 여러 변수와 함수를 export하고 있는데요.
// cal.js
export let a = 10,
b = 20,
result = 0;
export function sum() {
result = a + b;
return result;
}
export function multiply() {
result = a * b;
return result;
}아래 app.js 모듈에서는 cal.js 모듈에서 export한 걸 import하고 있습니다.
//app.js
import {a, b, result, sum, multiply } from './cal.js';
sum();
console.log(result); // 30
multiply();
console.log(result); // 200
여러 개를 import 하려면 괄호 { } 안에 그냥 나열하면 여러 개를 동시에 import 할 수 있습니다.
타입스크립트 코드에서 아래와 같은 형식을 많이 보셨을 듯싶은데요.
전체 모듈을 우리가 지정한 이름의 객체로 한꺼번에 import하는 방식입니다.
import * as cal from './cal.js';이렇게 import하면 cal.js 파일의 변수나 함수는 객체 cal의 속성으로 참조할 수 있습니다.
cal.a;
cal.b;
cal.sum();이런 방식을 영어로는 ‘Namespace Import’라고 부릅니다.
그리고 import에 있어 중요한 게 아래 코드처럼 한 개의 모듈을 여러 번 import한다고 해도 해당 모듈은 한 번만 실행된다는 점입니다.
import { a } from './cal.js';
import { b } from './cal.js';
import { result } rom './cal.js';위 코드에서 첫 번째 줄이 실행되면 cal.js는 메모리에 로드되고, 두 번째 줄이 실행될 때 한번 로드된 cal.js 모듈을 메모리상에서 재사용하는 방식입니다.
그래서, cal.js 모듈에 있는 명령어는 한 번만 실행된다는 뜻입니다.
임포트(import)나 익스포트(export)에 있어 제한 사항이 있는데요.
바로 import나 export 명령은 다른 명령어나 함수 바깥에 위치해야 한다는 뜻입니다.
그냥 단순하게 import나 export를 함수 안에서는 사용할 수 없다고 이해하시면 됩니다.
if ( requiredSum) {
export sum;
}
function importSum() {
import { sum } from './cal.js';
}위와 같이 export, import를 함수 안에서 사용하면 안 됩니다.
왜냐하면 자바스크립트에서는 import, export할 대상이 정적으로 정해져야 하기 때문입니다.
참고로 ES6의 다음 버전인 ES2020에서는 다이내믹하게 import 할 수 있는 import() 객체가 도입되었는데요.
오늘은 ES6를 공부하는 날이니까 다음에 알아보도록 하겠습니다.
자바스크립트에서는 import할 때나 export할때 별칭을 지정할 수 있는데요.
바로 아래와 같이 as 키워드를 쓰면 됩니다.
// math.js
function add( a, b ) {
return a + b;
}
export { add as sum };import { sum as total } from './math.js';위와 같이 export 할 때 add 함수를 sum이라는 별칭 이름으로 export했습니다.
그리고 import할 때는 sum이라는 함수를 total이라는 별칭으로 import했습니다.
ES6에서는 import한 걸 바로 export할 수 있는데요.
아래와 같은 코드가 있다고 합시다.
import { sum } from './math.js';
export { sum };위 코드에서는 math.js 모듈에서 import한 sum을 export하고 있는데요.
이런 방식을 Re-exporting이라고 합니다.
그리고 이론적으로는 위 코드에서 두 줄이나 소비됐던 코드가 아래 코드처럼 한 줄로 처리할 수 있습니다.
export { sum } from './math.js';조금 헷갈릴 수 있는데요.
아래도 가능합니다.
export { sum as add } from './math.js';
export * from './cal.js';우리가 보통 export할 때 한 개의 디폴트 export를 지정할 수 있는데요.
오직 한 개의 default export만 가능합니다.
그냥 export default라고 지정하면 됩니다.
// sort.js
export default function(arr) {
// sorting here
}
그러면 import하는 방식은 괄호 ‘{ }‘를 쓰지 않고 그냥 import하면 됩니다.
import sort from sort.js;
sort([2,1,3])그리고 디폴트와 디폴트가 아닌걸 import할 때는 꼭 디폴트 import를 먼저 써야 합니다.
// sort.js
export default function(arr) {
// sorting here
}
export function heapSort(arr) {
// heapsort
}아래와 같이 디폴트로 지정된 걸 먼저 import해야 합니다.
import sort, {heapSort} from './sort.js';
sort([2,1,3]);
heapSort([3,1,2]);그리고 디폴트도 별칭을 통해 import할 수 있습니다.
import { default as quicksort, heapSort} from './sort.js';이상으로 ES6 모듈의 import, export 방식에 대해 알아보았습니다.
그럼.