LoginSignup
7
11

More than 5 years have passed since last update.

require()/importの副作用

Posted at

JavaScriptでもモジュール化したプログラミングが定着してきましたが、モジュールの読み込みの際には副作用が発生することに気をつけないといけません。

副作用とは

「副作用」といっても、医薬品の場合は何がメインの作用で何が副作用かは相対的なものですが(風邪薬の「眠くなる」副作用をメインとした睡眠改善薬のように、状況によって何を主たる作用と考えるかは変わります)、プログラミング用語としては、「副作用」の意味は一定しています。

ある処理が、引数と返り値以外に及ぼす影響

具体的には、以下の様なものがあります。

  • 処理の実行を越えて残る変数への代入、破壊的変更
  • 入出力、通信など、プログラム外部とのやり取り

例えば、「alert()でメッセージを表示させる」ようなことも、通常それを目的に行いますが、これも分類は副作用です。

require()の動作と、副作用

Webpackなどでコンパイルするとわかりやすいですが、個々のファイル(モジュール)は、requiremoduleなどを引数として渡される関数、という形に変換されます。そして、require()を呼んだ場合には、以下のような処理が走ります。

  1. モジュールリストから、当該のモジュールが用意されているかをチェックする。
  2. 用意されていない場合、モジュール定義をラップした関数を呼び出して、module.exportsなどの値を取得する
  3. エクスポートされた値を返す

ということで、以下のようなことがわかります。

  • モジュールに書いた、exports以外のコードが実行されるのは最大1回(次からはキャッシュされる)
  • モジュールごとの実行順は呼んだ順

どんなコードを書く?

もちろん、module.exports =以下の一文で済ませてしまう場合であれば副作用が発生する余地もありませんし、逆に「requireしただけでalert()を吐く」ようなモジュールも、実用的ではないでしょう。ただ、現実には副作用として何か実行することも十分ありえます。

  • 他のモジュールのrequire
  • イベントの設定
  • グローバルや他のモジュールによる変数の、破壊的な変更
    • コンポーネント系フレームワークの、コンポーネントの登録
    • jQueryプラグインの設定1

副作用をしっかり考えないといけない場合

これらの副作用の中で、比較的影響しうるのが、「イベント設定」です。状況によっては、イベント設定に際して「順番」を考えないといけない場面があります。

たとえば、path/too/foo/firstpath/too/foo/secondより先にセットしないとうまく動かない、となったとします。そんな場合には、「とりあえずrequireして読み捨て」で乗り切ることができます。

path/too/foo/second.js
// firstの副作用が先に動くことを保証する
require('./first');

document.addEventListenr(....);

import/export

importexportは何かしらの宣言文のようにも見えますが、「JavaScriptを実行して特定の値を取得する」という基本は、require/exportsの組と同じです。ということで、副作用についても同様に考えないといけません。


  1. もっとも、セットしたプラグインがrequire()の結果にならないことを考えると、相性の悪さは否めません。 

7
11
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
7
11