5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ひとりJavaScriptAdvent Calendar 2022

Day 12

import/export, require/exports って何が違うの?

Last updated at Posted at 2022-12-13

いつまで経っても使い分けが分からないので調べてみました。

モジュールとは

まずは「モジュール」について理解する必要があります。
モジュールとは JavaScript プログラムの一部を分割したものです。

何かアプリを作成するときには1つのファイルに全てを書き込むのではなく、メインのファイル + 一部機能に特化したファイル という構成にしますよね。このうち一部の機能に特化したファイルをモジュールといいます。

当然分割しっぱなしではいけないので、メインのファイルからモジュールを読み込んで使う必要がありますね。
import/export や require/exports はそんなモジュールを利用するために存在する構文です。

import/export

ネイティブの JavaScript モジュール機能は、import と export 文を利用します。

JavaScript モジュール - JavaScript | MDN

つまり Node.js 環境である必要はなく、ブラウザの JavsScript で動作します。2つの種類があります。

  • 複数の値をエクスポートする「名前付きエクスポート
  • 1つの値をエクスポートする「デフォルトエクスポート

さっそく試してみましょう。

※ file:// の URL ではモジュールが使えず CORS エラーとなってしまうため、LiveServer などで立ち上げましょう

<!DOCTYPE html>
<html lang="js">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>モジュールのテスト</title>
</head>
<body>
  <p>HTMLページです</p>
  <script type="module" src="./script.js"></script>
</body>
</html>

こんな感じで HTML ページを作成しました。 script タグを読み込む際に type="module" とつけるのがポイントです。

script.js はこのように書いてみましょう。

const body = document.body;

const p = document.createElement("p");
p.innerText = "メインの js ファイルです";

body.appendChild(p);

こんな感じでページが表示されたかと思います。

ページ画像

では import/export でモジュールの読み込みを試してみましょう! 手元で試す場合、以下のようなファイル構成にしてください。

├── module/
│   ├── module.js
├── index.html
├── script.js

では module.js を書いていきましょう。

const p = document.createElement("p");
p.innerText = "モジュールの js ファイルです";

export default p;

ここで使っているのは デフォルトエクスポート です。変数 p のみをエクスポートしています。ではインポート側を見てみましょう。 script.js を少し編集します。

// + ここを追加
import moduleP from "./module/module.js"

const body = document.body;

const p = document.createElement("p");
p.innerText = "メインの js ファイルです";

body.appendChild(p);

// + ここを追加
body.appendChild(moduleP);

p という変数名が被ってしまうので、 import moduleP from "./module/module.js" というふうにモジュール側の変数名を変更しています。便利ですね。

実行すると以下のようになるはずです。

ページ画像

index.html から読み込みしていない、 module.js で作成した p タグを表示できていますね!

ではもう1つのエクスポート方法、名前付きエクスポートを使ってみましょう。module からさらに他のものをエクスポートしたいとしましょう。

const moduleP = document.createElement("p");
moduleP.innerText = "モジュールの js ファイルです";

// + ここを追加
const clickHandler = (e) => {
  console.log("clicked")
}

// - ここを削除
// export default p;

// + ここを追加
export { moduleP, clickHandler };

p タグにイベントハンドラを追加してからエクスポートすればいい話なのであまりいい例ではないですが、インポートしてみましょう。

// + ここを追加
import * as module from "./module/module.js"
const { moduleP, clickHandler } = module;

// - ここを削除
// import moduleP from "./module/module.js"

const body = document.body;

const p = document.createElement("p");
p.innerText = "メインの js ファイルです";

// + ここを追加
moduleP.addEventListener("click", clickHandler);

body.appendChild(p);
body.appendChild(moduleP);

名前付きエクスポートされた変数たちはオブジェクトの形でインポートされるので、分割代入を使って取り出しています。
このように動作するはずです。

ページ画像

関数もエクスポートすることができましたね!

ちなみに2つのエクスポート方法は併用可能です。

また import/export はブラウザでしか使えないという表現は正確ではなく、Babel などでトランスパイルすれば Node.js 環境でも使えます。

require/exports

こちらは Node.js の環境で動作するモジュールを読み込む構文です。
外部のライブラリを読み込むためにも使われますが、今回は import/export と比較するために自分でエクスポートしたものを要求(require)してみましょう。
以下のようなファイル

├── package.json
├── module/
│   ├── module.js
├── index.js
index.js
const modules = require("./modules/module");

const sayHello = () => {
  return "Hello!";
}

const { sayMorning } = modules;

console.log(sayHello());
console.log(sayMorning());
module.js
exports.sayMorning = () => {
  return "Good morning!";
}

以下のようになったでしょうか。

ターミナル

index.jsmodule.js、両方の関数の実行結果がコンソールに出力されましたね。

注目すべきはやはり exportsexport がややこしい! ということでしょうか。
正確な由来はわからないのですが、 exports の性質として exports.〇〇 でいくらでもエクスポートできる点が挙げられます。
export はデフォルトエクスポートで使う場合もあるので複数形とは限らない、と一旦こじつけて覚えようと思います。

require/exports はブラウザでそのまま使うことができず、やはりこちらもトランスパイルする必要があります。

まとめ

  • import/export: ブラウザの JavaScript で使える
    • デフォルトエクスポートは1つだけ変数をエクスポートできる
    • 名前付きエクスポートならオブジェクトの形で複数の変数をエクスポートできる
  • require/exports: Node.js 環境で使える
    • exports.〇〇, const obj = require("{ path }")` の形で使う

-> そもそも使う環境が違う!

※ トランスパイルしてもう片方の環境で使うことも可能

参考資料

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?