Michi's Tech Blog

一人前のWebエンジニアを目指して

【JavaScript】インポート/エクスポートルールの整理

こんにちは!
スマレジ テックファームのMichiです!

JavaScriptのインポートとエクスポートのルールってたくさんあってややこしいですよね...。
というわけで、今回の記事で整理していきたいと思います。

基本形

個別にエクスポートする

変数、関数、クラスのぞれぞれは、宣言前にexportをつけることで、個別にエクスポートすることができます。

input.js

// 変数のエクスポート
export const name = "Michi";

// 関数のエクスポート
export function hello() {
  console.log("Hello");
}

// クラスのエクスポート
export class Member {
  constructor(lastName, firstName) {
    this.lastName = lastName;
    this.firstName = firstName;
  }

  getName() {
    return this.lastName + " " + this.firstName;
  }
}

まとめてエクスポートする

ブラケット{}を使用することで、まとめてエクスポートすることができます。

input.js

const name = 'Michi'

function hello() {
  console.log('Hello')
}

class Member {
  constructor(lastName, firstName) {
    this.lastName = lastName
    this.firstName = firstName
  }

  getName() {
    return this.lastName + ' ' + this.firstName
  }
}

// まとめてエクスポート
export { name, hello, Member }

インポートする

エクスポートしたそれぞれの変数、関数、クラスは、import宣言をすることによって、別モジュールで使用できます。
インポートするものは、ブラケット{}の中に羅列します。

output.js

// input.jsからインポート
import { name, hello, Member } from './input.js'

console.log(name) // 結果:Michi
hello() // 結果:Hello
const member1 = new Member('山田', '太郎')
console.log(member1.getName()) // 結果:山田 太郎

一括でインポートする

インポートするものの量が多い場合は、import * as <obj>という構文で、オブジェクトとして一括インポートできます。
それらを使用したいときは、<obj>.<呼び出したい変数・関数・クラス>という形で呼び出します。

output.js

// オブジェクトとして一括インポート
import * as input from './input.js'

console.log(input.name) // 結果:Michi
input.hello() // 結果:Hello
const member1 = new input.Member('山田', '太郎')
console.log(member1.getName()) // 結果:山田 太郎

ただし、この形はあまり推奨しません。 理由は、

  • 呼び出し時のコードが長くなるから:console.log(name)console.log(input.name)
  • インポートしたものが、いつどこで使われているのか分かりにくいから

import { name, hello, Member } from './input.js'のように、明示的にインポートする方がおススメです。

別名を使う

asを利用することで、別名でエクスポート/インポートできます。

別名エクスポート

input.js

class Member {
  constructor(lastName, firstName) {
    this.lastName = lastName
    this.firstName = firstName
  }

  getName() {
    return this.lastName + ' ' + this.firstName
  }
}

// 別名でエクスポート
export { Member as Person }

output.js

import { Person } from './input.js'

const member1 = new Person('山田', '太郎')
console.log(member1.getName()) // 結果:山田 太郎

別名インポート

input.js

export class Member {
  constructor(lastName, firstName) {
    this.lastName = lastName
    this.firstName = firstName
  }

  getName() {
    return this.lastName + ' ' + this.firstName
  }
}

output.js

import { Member as Person } from './input.js'

const member1 = new Person('山田', '太郎')
console.log(member1.getName()) // 結果:山田 太郎

デフォルトエクスポート

デフォルトエクスポートとは

モジュールの中にエクスポートするものが1つしかない場合は、デフォルトエクスポートを使用することができます。
使い方はexport宣言の後に、defaultを付けるだけです。

member.js

// デフォルトエクスポート
export default class {
  constructor(lastName, firstName) {
    this.lastName = lastName
    this.firstName = firstName
  }

  getName() {
    return this.lastName + ' ' + this.firstName
  }
}

この場合、エクスポートする関数/クラスに名前を付ける必要はありません。
なぜなら、エクスポートされるものは1つしかないので、名前で識別する必要ながないためです。

デフォルトエクスポートをインポートする場合は、インポート側で変数(仮の名前)を付けてあげる必要があります。
またこの場合、ブラケット{}は不要です。

output.js

// Memberという変数を付ける
import Member from './member.js'

const member1 = new Member('山田', '太郎')
console.log(member1.getName()) // 結果:山田 太郎

デフォルトエクスポート時のファイル名

ところで先ほど、input側のファイルを以前までの例と違い、member.jsという名前に変えていたのにお気づきでしょうか?
これはコードの一貫性を保つために、インポートされた変数はファイル名に対応するべきという規則があるからです。例えば、input.jsというファイルからデフォルトエクスポートされた場合、インポート側(output.js)からはどんな名前でもインポートできます。

output.js

// どんな名前でもインポートできる
import input from './input.js'
import Member from './input.js'
import hoge from './input.js'

しかし、インポートの変数名とファイル名が乖離していると、余計な混乱が生じます。ですので、この場合はエクスポートされたモジュールの内容を表すmemberという名前で、変数名とファイル名を統一するべきです。

まとめ

JavaScriptのインポート/エクスポートルールについて解説しました。
JavaScriptは明示的にexportを書かないといけないのがやっかいですよね。Pythonみたいにimportだけで済めばいいんだけどなあ。