Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8892

JavaScriptでのimport/export方法

$
0
0

JavaScriptでは、exportやimportを使って関数やクラスを他のファイルから呼び出し/読み込みすることができますが、いろんな書き方があって何がどう違うのかごちゃごちゃしませんか?
少なくとも私はごちゃごちゃしちゃうので、備忘録も兼ねてまとめたいと思います。

es2015とNode.jsでの書き方の違い

まず最初の混乱ポイントは、
exportなのか exports(module.exports)なのか?
読み込みは importrequireどっちなの?

めちゃくちゃややこしいですよね。けどこれ実は別物で、
export/importは、ES2015(ES6)での書き方
exports/requireは、Node.js(CommonJS)での書き方なんです。

参考:CommonJSって何?という方は @naoki_mochizukiさんが書かれた JavaScriptが辿った変遷という記事を読んでみてください!JavaScriptの歴史がとてもわかりやすく説明されていて、CommonJSの正体もスッと理解できると思います!

以下に書き方を例を使ってまとめていきます。

export 方法一覧

ES2015(ES6)での書き方

1. 個々の機能をエクスポート

exportconstname="xxx";exportfunctionfuncName(){...}exportclassclassName{...}

2. 事前に宣言された機能をまとめてエクスポート

export{name,funcName,className};

3. デフォルトとして個別の機能をエクスポート

exportdefaultfunction(){}// orexportdefault{name,funcName,className}

Node.js(CommonJS)での書き方

4. 単一のモジュールをエクスポート

module.exports=xxx;

5. エクスポートしたい個別の機能を指定し、オブジェクトとしてエクスポート

module.exports={xxx,yyy};module.exports={xxxName:xxx,yyyName:yyy};

import 方法一覧

ES2015(ES6)での書き方

1. モジュールから特定のエクスポートをインポートする

import{xxx}from"./lib"import{xxx,yyy}from"./lib"

2. モジュールのコンテンツすべてをインポート

import*aslibfrom"./lib"

3. デフォルトをインポート

importxxxfrom"./lib"

Node.js(CommonJS)での書き方

4. エクスポートされたものをまとめてインポート

constxxx=require("./lib")

5. エクスポートされたものを個別にプロパティ名を指定してインポート

const{xxx,yyy}=require("./lib")

使用例

それでは、実際のコードの例を見て見ましょう。

ES2015(ES6)の場合

例1

export1.js
exportconstadd=(num1,num2)=>{returnnum1+num2;};exportconstminus=(num1,num2)=>{returnnum1-num2;};
import1.js
import{add,minus}from'./export1.js';add(1,2);// => 3minus(1,2);// => -1

個々の機能をエクスポートする場合、インポートしたい物を {} で括って個別に呼び出します。

例2

export2
constadd=(num1,num2)=>{returnnum1+num2;};constminus=(num1,num2)=>{returnnum1-num2;};export{add,minus};
import2.js
import{add,minus}from'./export2.js';add(1,2);// => 3minus(1,2);// => -1

事前に宣言された機能をまとめてエクスポートした場合も同じ。
インポートしたい物を {} で括って個別に呼び出します。

例3

export3
constadd=(num1,num2)=>{returnnum1+num2;};constminus=(num1,num2)=>{returnnum1-num2;};export{add,minus};
import3.js
import*ascalcfrom'./export3.js';console.log(calc);// => [Module] { add: [Function: add], minus: [Function: minus] }calc.add(1,2);// => 3calc.minus(1,2);// => -1

これは、calcという名前で export3.js のファイルのモジュールからのエクスポートすべてインポートします、という書き方です。

例4

export4
constadd=(num1,num2)=>{returnnum1+num2;};constminus=(num1,num2)=>{returnnum1-num2;};exportdefault{add,minus};
import4.js
importcalcfrom'./export4.js';console.log(calc);// => { add: [Function: add], minus: [Function: minus] }calc.add(1,2);// => 3calc.minus(1,2);// => -1

export defaultでエクスポートすると、インポート時に {} で括る必要がなく、まとめてインポートされます。

例5

export5.js
exportdefaultfunctionadd(num1,num2){returnnum1+num2;}
import5.js
importaddfrom'./export5.js';console.log(add(1,2));// => 3

export defaultする時には、個別の機能をダイレクトにエクスポートすると、インポートしたものをそのまま使用できます。

:warning:注意 :warning:
コマンドでこれらのファイルを実行する時に、下記のように nodeコマンドで実行しても、エラーが出て期待通りに実行できません。

$ node import5.js
/User/xxx/import5.js:1
import add from './export5.js';
^^^^^^

SyntaxError: Cannot use import statement outside a module
(エラーが続きます...)

なぜなら、ES2015(ES6) で書かれたコードは node コマンドでそのまま実行できないからです。

実行したい場合は、babel などのトランスパイラを使って ES2015(ES6) で書かれた JavaScript を Node.js が理解してくれるようにトランスパイルするなどの一手間を加える必要があります。

けど、今回はその環境を作るのがちょっとめんどくさかったので、下記オプションを付けて確認しました。
--experimental-modulesの説明は割愛します。)

$ node --experimental-modules import5.js 
(node:10746) ExperimentalWarning: The ESM module loader is experimental.
3

Node.js(CommonJS)の場合

例6

export6.js
constadd=(num1,num2)=>{returnnum1+num2;};constminus=(num1,num2)=>{returnnum1-num2;};module.exports=add;
import6.js
constadd=require('./export6');add(2,3);// => 5

import6.js でインポートする時に
const { add } = require('./export');という風に{} で括ってしまうと、
add(2, 3)実行時にエラーになってしまいます。

なぜでしょうか??

exportされているのは add
すなわち、関数自体が export されているのですが、addというプロパティ名でエクスポートされたものをインポートしようとしているので、そんなプロパティは存在しないよ、とエラーが発生してしまいます。

では次の例はどうなるでしょうか。

例7

export7.js
constadd=(num1,num2)=>{returnnum1+num2;};constminus=(num1,num2)=>{returnnum1-num2;};module.exports={add,minus};
import7-1.js
constadd=require('./export7');add.add(2,3)// => 5add.minus(2,3)// => -1add(2,3);// エラー

exports7.js では個々の関数をオブジェクトとしてエクスポートしているので、import7-1.jsのaddには、
{ add: [Function: add], minus: [Function: minus] }
というオブジェクトが代入されているのです。

ではもし、下記のように {} で括ってインポートしたらどうなるでしょうか。

import7-2.js
const{add,minus}=require('./export7');add(2,3)// => 5minus(2,3)// => -1

それぞれの変数には対応するプロパティの値、すなわち関数が代入されるので、そのまま関数として実行できるようになります。

最後に、これは少し極端な例を見てみましょう。

例8

export8.js
constadd=(num1,num2)=>{returnnum1+num2;};constminus=(num1,num2)=>{returnnum1-num2;};module.exports={addName:add,minusName:minus};
import8.js
const{addName,minusName}=require('./export8');addName(2,3)// => 5minusName(2,3)// => -1

もう何が起こっているかはわかりますね!
export8.js で、addという名前の関数を addNameというプロパティ名でエクスポートしているので、{ addName }でインポートしてあげる必要がありますね。

もしこれを const func = require('./export');とインポートしたら、
func.addName(2, 3)といった感じで呼び出してあげればOKです!

参考


Viewing all articles
Browse latest Browse all 8892

Trending Articles