export
export (모듈 내보내기)
export 선언은 JavaScript 모듈에서 값을 내보내는 데 사용합니다. 내보낸 값은 import 선언 또는 동적 import()를 통해 다른 프로그램에서 가져올 수 있습니다. 원문은 MDN의 JavaScript 참고 문서입니다.
본문
export 선언은 JavaScript 모듈에서 값을 내보내는 데 사용됩니다. 내보낸 값은 import 선언이나 동적 import로 다른 프로그램에서 가져올 수 있습니다. 가져온 바인딩의 값은 그것을 내보낸 모듈에서 변경될 수 있습니다 — 모듈이 내보내는 바인딩의 값을 갱신하면, 그 갱신은 가져온 값에도 반영되어 보입니다.
소스 파일에서 export 선언을 사용하려면 해당 파일이 런타임에 모듈로 해석되어야 합니다. HTML에서는 <script> 태그에 type="module"을 추가하거나 다른 모듈에 의해 import되어야 합니다. 모듈은 자동으로 strict mode(엄격 모드)로 해석됩니다.
문법 (Syntax)
// 내보내기 선언 (Exporting declarations)
export let name1, name2/*, … */; // also var
export const name1 = 1, name2 = 2/*, … */; // also var, let
export function functionName() { /* … */ }
export class ClassName { /* … */ }
export function* generatorFunctionName() { /* … */ }
export const { name1, name2: bar } = o;
export const [ name1, name2 ] = array;
// 내보내기 목록 (Export list)
export { name1, /* …, */ nameN };
export { variable1 as name1, variable2 as name2, /* …, */ nameN };
export { variable1 as "string name" };
export { name1 as default /*, … */ };
// 기본 내보내기 (Default exports)
export default expression;
export default function functionName() { /* … */ }
export default class ClassName { /* … */ }
export default function* generatorFunctionName() { /* … */ }
export default function () { /* … */ }
export default class { /* … */ }
export default function* () { /* … */ }
// 모듈 통합 (Aggregating modules)
export * from "module-name";
export * as name1 from "module-name";
export { name1, /* …, */ nameN } from "module-name";
export { import1 as name1, import2 as name2, /* …, */ nameN } from "module-name";
export { default, /* …, */ } from "module-name";
export { default as name1 } from "module-name";
nameN: 내보낼 식별자입니다(다른 스크립트에서import를 통해 가져올 수 있도록).as로 별칭을 사용하면 실제 내보내는 이름을 문자열 리터럴로 지정할 수 있으며, 이때 이름은 유효한 식별자가 아닐 수도 있습니다.
설명 (Description)
모든 모듈은 명명된 내보내기(named export)와 기본 내보내기(default export) 두 가지 종류의 내보내기를 가질 수 있습니다. 모듈당 명명된 내보내기는 여러 개 가질 수 있지만 기본 내보내기는 하나만 가질 수 있습니다.
명명된 내보내기(Named exports).
// 다른 곳에서 선언된 기능을 export
export { myFunction2, myVariable2 };
// 개별 기능을 export (var, let, const, function, class 가능)
export let myVariable = Math.sqrt(2);
export function myFunction() {
// …
}
export 키워드 뒤에는 let, const, var 선언뿐 아니라 function이나 class 선언도 사용할 수 있습니다. 또한 export { name1, name2 } 문법으로 다른 곳에서 선언된 이름 목록을 내보낼 수도 있습니다. 참고로 export {}는 빈 객체를 내보내는 것이 아니라, 아무것도 내보내지 않는 no-op 선언입니다(빈 이름 목록).
export를 using이나 await using 선언에는 사용할 수 없습니다. 다만 다른 곳에서 using/await using으로 선언된 변수를 내보내는 것은 가능하지만, 그 변수는 모듈이 실행을 마치는 즉시 dispose되므로 모든 import 쪽이 이미 dispose된 값을 받게 되어 강력히 권장되지 않습니다.
export using resource1 = getResource(); // SyntaxError
// 문법상 허용되지만 권장되지 않음
using resource2 = getResource();
export { resource2 };
내보내기 선언은 temporal dead zone(시간적 사각지대) 규칙의 적용을 받지 않습니다. 이름 X 자체가 선언되기 전에 해당 모듈이 X를 내보낸다고 선언할 수 있습니다.
export { x };
const x = 1;
// 동작합니다. `export`는 단지 선언일 뿐 `x`의 값을 사용하지 않기 때문입니다.
기본 내보내기(Default exports).
// 다른 곳에서 선언된 기능을 default로 export
export { myFunction as default };
// 위와 동일:
export default myFunction;
// 개별 기능을 default로 export
export default function () { /* … */ }
export default class { /* … */ }
참고: export 선언의 이름들은 서로 구별되어야 합니다. 중복된 이름의 export가 있거나 둘 이상의 default export를 사용하면 SyntaxError가 발생하고 모듈이 평가되지 않습니다.
export default 문법은 어떤 표현식이든 허용합니다. 예: export default 1 + 1;
특수한 경우로, 함수와 클래스는 표현식이 아니라 선언으로 내보내지며, 이 선언은 익명(anonymous)일 수 있습니다. 즉 함수는 호이스팅(hoisting)됩니다.
// `foo`가 함수 선언이지 함수 표현식이 아니므로 동작합니다.
foo();
export default function foo() {
console.log("Hi");
}
// 기술적으로는 여전히 선언이지만 익명이어도 허용됩니다.
export default function () {
console.log("Hi");
}
명명된 내보내기는 여러 값을 내보내야 할 때 유용합니다. 이 모듈을 import할 때 명명된 내보내기는 정확히 같은 이름으로 참조해야 하며(as로 이름을 바꿀 수 있음), 기본 내보내기는 어떤 이름으로든 import할 수 있습니다.
// file test.js
const k = 12;
export default k;
// some other file
import m from "./test"; // k가 default export이므로 import m 대신 import k를 쓸 자유가 있습니다.
console.log(m); // 12
명명된 내보내기를 이름 충돌 방지를 위해 바꿀 수도 있습니다.
export { myFunction as function1, myVariable as variable };
문자열 리터럴을 사용하면 유효한 식별자가 아닌 이름으로 바꿀 수도 있습니다. 예: export { myFunction as "my-function" };
재내보내기 / 통합 (Re-exporting / Aggregating). 모듈은 별도의 import/export 문 두 개를 쓰는 번거로움 없이 다른 모듈에서 내보낸 값을 "중계(relay)"할 수 있습니다. 여러 모듈의 다양한 export를 한 모듈로 모을 때 유용하며, 이를 보통 "배럴 모듈(barrel module)"이라고 합니다.
export ... from ... 문법으로 이를 달성할 수 있습니다.
export { default as function1, function2 } from "bar.js";
이는 import + export의 조합과 비슷하지만, function1과 function2가 현재 모듈 내부에서 사용 가능해지지 않는다는 차이가 있습니다.
import { default as function1, function2 } from "bar.js";
export { function1, function2 };
대부분의 "import from" 문법에는 대응하는 "export from" 문법이 있습니다.
export { x } from "mod";
export { x as v } from "mod";
export * as ns from "mod";
또한 export * from "mod"도 있는데, import * from "mod"는 존재하지 않지만 export * from "mod"는 존재합니다. 이는 mod의 모든 명명된 export를 현재 모듈의 명명된 export로 다시 내보내지만, mod의 기본 export는 재내보내지 않습니다. 두 개의 와일드카드 export 문이 암묵적으로 같은 이름을 재내보내면 둘 다 재내보내지 않습니다.
// -- mod1.js --
export const a = 1;
// -- mod2.js --
export const a = 3;
// -- barrel.js --
export * from "./mod1.js";
export * from "./mod2.js";
// -- main.js --
import * as ns from "./barrel.js";
console.log(ns.a); // undefined
중복된 이름을 직접 import하려 하면 오류가 발생합니다.
import { a } from "./barrel.js";
// SyntaxError: The requested module './barrel.js' contains conflicting star exports for name 'a'
다음은 import 대응 문법이 있음에도 문법상 유효하지 않습니다.
export DefaultExport from "bar.js"; // Invalid
참고: 이 문법이 없기 때문에 import source에도 재내보내기 대응 문법이 없습니다. 올바른 방법은 export를 이름을 바꾸는 것입니다.
export { default as DefaultExport } from "bar.js";
"export from" 문법은 as 토큰을 생략할 수 있는데, 그러면 기본 export가 여전히 기본 export로 재내보내집니다.
export { default, function2 } from "bar.js";
export from은 import가 지원하는 모든 기능을 지원합니다. 예를 들어 import attributes도 지원합니다.
export { default } from "./data.json" with { type: "json" };
예제 (Examples)
명명된 내보내기 사용. 모듈 my-module.js에서:
// module "my-module.js"
function cube(x) {
return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
const graph = {
options: { color: "white", thickness: "2px" },
draw() { console.log("From graph draw function"); },
};
export { cube, foo, graph };
HTML 페이지에 포함된 최상위 모듈에서:
import { cube, foo, graph } from "./my-module.js";
graph.options = { color: "blue", thickness: "3px" };
graph.draw(); // "From graph draw function" 로그
console.log(cube(3)); // 27
console.log(foo); // 4.555806215962888
중요한 주의점: 이 스크립트를 모듈로 인식시켜 적절히 처리하려면 HTML에서 <script> 요소에 type="module"을 써야 합니다. 또한 JS 모듈은 file:// URL로는 실행할 수 없습니다(CORS 오류가 발생). HTTP 서버를 통해 실행해야 합니다.
기본 내보내기 사용. 모듈 전체를 나타내는 단일 값은 기본 내보내기를 사용합니다.
// module "cube.js"
export default function cube(x) {
return x * x * x;
}
다른 스크립트에서 기본 내보내기를 간단히 import합니다: import cube from "./cube.js"; 그 후 console.log(cube(3)); // 27.
export from 사용. childModule1.js(myFunction과 myVariable export), childModule2.js(MyClass export), parentModule.js(단순 취합만 수행), 최상위 모듈(parentModule의 export를 소비)로 구성된 계층 예시입니다.
// In childModule1.js
function myFunction() { console.log("Hello!"); }
const myVariable = 1;
export { myFunction, myVariable };
// In childModule2.js
export class MyClass { /* … */ }
// In parentModule.js
export { myFunction, myVariable } from "childModule1.js";
export { MyClass } from "childModule2.js";
사양 및 호환성
export는 ECMAScript 사양에서 정의되며, Baseline "Widely available"로 분류되어 2018년 5월부터 브라우저 전반에서 사용 가능했습니다.
더 알아보기
- import
- import()
- import.meta
- JavaScript modules 안내
- ES modules: A cartoon deep-dive (hacks.mozilla.org)