JavaScript | ES6+ 文法:モジュール – import / export 基本

JavaScript JavaScript
スポンサーリンク

モジュールの考え方(まず全体像から)

モジュールは、「ファイルごとに役割を分けて、必要なものだけをやり取りする仕組み」です。
1ファイル = 1モジュール、と考えておけばOKです。

  • 「このファイルから外に出すもの」を export する
  • 「他のファイルから持ってくるもの」を import する

というルールで、コードをきれいに分割していきます。

// math.js (モジュール)
// 外に出したい関数を export
export function add(a, b) {
  return a + b;
}
JavaScript
// main.js (別モジュール)
// 他のファイルから関数を import
import { add } from "./math.js";

console.log(add(2, 3)); // 5
JavaScript

ここが重要です。
「export されたものだけが、他のファイルから使える」
export されていない変数や関数は、そのファイルの中だけの「内緒」です。


export の基本(何を外に出すか決める)

名前付き export(複数 export したいときの基本形)

一番よく使うのが「名前付き export」です。
export を付けたものだけが、そのモジュールの「公開API」になります。

// math.js
export const PI = 3.14;

export function add(a, b) {
  return a + b;
}

export function sub(a, b) {
  return a - b;
}

// これは export していないので外から見えない
const secret = "hidden";
JavaScript

このファイルでは、PI, add, sub の3つが外に出ていて、secret は中だけの存在です。

あとからまとめて export する書き方もあります。

// math.js
const PI = 3.14;
function add(a, b) { return a + b; }
function sub(a, b) { return a - b; }

export { PI, add, sub };  // まとめて export
JavaScript

デフォルト export(そのモジュールの「主役」を1つだけ)

1つのモジュールに「これがメイン!」というものがある場合、export default を使えます。
各モジュールにつき、default は1つだけです。

// greet.js
export default function greet(name) {
  console.log(`Hello, ${name}`);
}
JavaScript

変数でもクラスでもOKです。

// User.js
export default class User {
  constructor(name) {
    this.name = name;
  }
}
JavaScript

ここが重要です。
名前付き export は何個でも OK、default export は1つだけ
default は「このファイルの看板」のようなものです。


import の基本(他のファイルから使わせてもらう)

名前付き import({} で指定して持ってくる)

名前付き export を持ってくるときは、{} を使います。

// math.js
export const PI = 3.14;
export function add(a, b) { return a + b; }
export function sub(a, b) { return a - b; }
JavaScript
// main.js
import { PI, add } from "./math.js";

console.log(PI);        // 3.14
console.log(add(2, 3)); // 5
JavaScript

{ PI, add } の部分の名前は、export 側の名前と一致している必要があります。

名前を変えて import したいときは as を使います。

import { add as plus } from "./math.js";

console.log(plus(2, 3)); // 5
JavaScript

default import(名前を自由につけて持ってくる)

default export を import するときは、{} なしで書きます。

// greet.js
export default function greet(name) {
  console.log(`Hello, ${name}`);
}
JavaScript
// main.js
import greet from "./greet.js";
//    ↑ 好きな名前で OK

greet("Alice");
JavaScript

同じ default export を、別のファイルで別名として import しても構いません。

import hello from "./greet.js";
hello("Bob");
JavaScript

ここが重要です。
default import は {} を付けないで書き、名前は自由につけられる
名前付き import は {} 付きで、名前を揃える(または as で変える)必要があります。

default と名前付きを同時に import する

1つのファイルから、default と名前付きの両方を export している場合もあります。

// user.js
export default class User {
  constructor(name) {
    this.name = name;
  }
}

export function createGuest() {
  return new User("Guest");
}
JavaScript

これを import するときはこう書けます。

// main.js
import User, { createGuest } from "./user.js";

const u1 = new User("Alice");
const u2 = createGuest();
JavaScript

ファイルパスと拡張子の扱い(つまずきポイント)

相対パスで指定する(./ や ../ から始まる)

ブラウザの ES モジュールでは、import のパスに必ず ./../ を付けます。

import { add } from "./math.js";   // 同じフォルダ
import { add } from "../lib/math.js"; // 1つ上のフォルダ
JavaScript

"math" のように書くと、ブラウザでは基本的にエラーになります(バンドラーなし前提)。
必ず "./xxx.js" のように書く習慣をつけてください。

拡張子 .js を付ける(ブラウザ ES モジュールの場合)

ブラウザで <script type="module"> を使う場合、基本的には .js 拡張子まで書きます。

import { add } from "./math.js"; // .js まで書く
JavaScript

Node.js やバンドラ(webpack, Vite など)を使うときは設定によって挙動が変わりますが、
初心者のうちは「ブラウザ ES モジュールでは .js まで書く」と覚えておけばOKです。


モジュールを使うと何が嬉しいのか(設計の視点)

ファイルごとに「責任」を分けられる

例えば、小さなアプリでも以下のように分けられます。

  • math.js:計算系の関数だけ
  • User.js:ユーザークラスだけ
  • api.js:サーバー通信だけ
  • main.js:アプリ全体の入口(他モジュールを組み合わせる)

main.js では「全体の流れ」に集中でき、
細かい処理はそれぞれのモジュールに任せられます。

// api.js
export async function fetchUser(id) {
  const res = await fetch(`/api/users/${id}`);
  return await res.json();
}
JavaScript
// main.js
import { fetchUser } from "./api.js";

async function main() {
  const user = await fetchUser(1);
  console.log(user);
}

main();
JavaScript

ここが重要です。
モジュールは「クラス」よりも大きい単位での設計道具です。
「何がどのファイルにいるべきか」を決めることで、プロジェクト全体が整理されます。

内部の実装を隠し、外には「必要なものだけ」出す

export していないものはそのファイル内だけで完結する「内部実装」です。

// password.js
function hash(text) {                 // export しない → 内部専用
  return `hash:${text}`;
}

export function createHashedPassword(raw) {
  return hash(raw);
}
JavaScript

外からは hash という関数があるかどうかも分かりません。
これはクラスのプライベートフィールドと同じ発想で、
「外から使わせたいもの(インターフェース)」と「内側のロジック」を分ける働きをします。


よくあるパターンと例題

例1:ユーティリティ関数モジュール

// stringUtils.js
export function capitalize(str) {
  if (!str) return "";
  return str[0].toUpperCase() + str.slice(1);
}

export function trimAll(str) {
  return str.trim();
}
JavaScript
// main.js
import { capitalize, trimAll } from "./stringUtils.js";

const raw = "  alice  ";
const name = capitalize(trimAll(raw));

console.log(name); // Alice
JavaScript

例2:クラスを default export する

// User.js
export default class User {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`こんにちは、${this.name} です`);
  }
}
JavaScript
// main.js
import User from "./User.js";

const u = new User("Alice");
u.greet();
JavaScript

例3:設定オブジェクトを export する

// config.js
export const API_BASE_URL = "https://api.example.com";
export const DEFAULT_LANG = "ja";
JavaScript
// main.js
import { API_BASE_URL, DEFAULT_LANG } from "./config.js";

console.log(API_BASE_URL, DEFAULT_LANG);
JavaScript

実際の HTML でモジュールを使うときの注意(ブラウザ)

type=”module” を付ける

ブラウザで ES モジュールを使うときは、
HTML でこう書きます。

<script type="module" src="./main.js"></script>
HTML

main.js の中で import / export を使えるようになります。
逆に、type="module" を付けずに import を書くとエラーになります。


まとめ

import / export の本質は、
「ファイル(モジュール)ごとに役割を分け、必要なものだけを明示的にやり取りする」 ことです。

押さえておきたいポイントを整理すると:

  • 1ファイル = 1モジュール、と考える
  • 他のファイルから使わせたいものに export を付ける
    • 名前付き export は {} で import
    • export default は1つだけ、名前を自由につけて import
  • import では必ずパスを書き、ブラウザ ES モジュールでは "./xxx.js" のように書く
  • export されていないものは、モジュール内だけの「内緒」
  • モジュールごとに「何を担当させるか」を決めることで、設計が楽になる

最初は小さなプロジェクトでも、
「1ファイルに全部書く」のをやめて、

「クラスや関連する関数を1ファイルにまとめて、それを export / import で繋ぐ」

というところから始めてみてください。
それだけで、コードの見通しがかなり変わってきます。

タイトルとURLをコピーしました