Posted at

[Node.js] requireなんてわかってる!ようでよくわかってなかったからいろいろ試した


はじめに


  1. Node.jsのrequireの挙動がおかしい!

  2. そういえばrequireの細かいところよくしらない

  3. いろいろ試してみよう

  4. 試したことを書いておこう


要約



これおかしいんちゃうんけ!どないなっとんねん!!

↓(色々試す)

わいがおかしいだけやんけ!!どうかしてたわ!!

調べてみたら「あたりまえやんけ」ってなることも

調べるまでは「あたりまえじゃない」ってことですね。

とりあえずほんの少しrequireに詳しくなれるかもしれない記事です。


ファイルに直で書かれた処理はrequireされたときに一度だけ評価される


index.js

const hoge1 = require("./hoge");

const hoge2 = require("./hoge");


hoge.js

console.log("Hoge");



index.jsの実行結果

Hoge


requireを2回しているけど、Hogeは1回しか表示されない。

requireするたびに評価されたらどうしようと思ったけど

評価されなかった、よかった。


exports.xxxしたプロパティは共有されるのか


index.js

const hoge1 = require("./hoge");

const hoge2 = require("./hoge");

console.log(hoge1.a);
console.log(hoge2.a);



hoge.js

exports.a = 0;



index.jsの実行結果

0

0

index.jsに以下の1行を入れたらどうなるか


index.js

const hoge1 = require("./hoge");

const hoge2 = require("./hoge");

+ hoge1.a = 10;
console.log(hoge1.a);
console.log(hoge2.a);


index.jsの実行結果

10

10

hoge1.aを変えたらhoge2.aも変わった。

requireは同じ参照先を返してくるらしい。


requireしたファイルの中の処理が評価されるタイミングは?


index.js

const hoge = require('./hoge');

console.log(hoge.a);
const foo = require('./foo');


hoge.js

console.log("Hoge");

exports.a = 0;


foo.js

console.log("Foo");



index.jsの実行結果

Hoge

0
Foo

requireしたタイミングで評価される。

ここらへんはインタプリタですなぁ。


fooの中でhogeの中身いじったら?


index.js

const hoge = require('./hoge');

console.log(hoge.a);
const foo = require('./foo');
+ console.log(hoge.a);


foo.js

console.log("Foo");


+ const hoge = require('./hoge');
+ hoge.a = "Fooの中で書き換えてやったぜ";


index.jsの実行結果

Hoge

0
Foo
+ Fooの中で書き換えてやったぜ

requireは同じ参照を返すわけだから

foo.jsの中でhoge.aを書き換えたらindex.jshoge.aにも影響する。

当然である。


なんかシングルトンに見えてきた

実際の動きから見えてくる事実や推測


  • 初めてrequireされた時に一度だけ中の処理が評価される

  • 2回目以降のrequireでは、1回目の時に評価されたモノ(インスタンス)の参照が戻ってくる。

すごくあれっぽいな

これって要するにシングルトンじゃないですか?

requireシングルトンをつくる関数に見えてきました。

これが


index.js

const hoge1 = require("./hoge");

const hoge2 = require("./hoge");

こう見えてきた感じ(要するにhogeのinstanceがくるんやろって見えてる目)


index.js

const hoge1 = hoge.instance;

const hoge2 = hoge.instance;


まとめ

結局何が知りたかったのか

const a = require('hoge');

const b = require('hoge');

果たしてabは同じものになるのか?

いや、同じじゃないと困るでしょって話だし結果同じもの入ってました。

どうにか違うものが返せないかと試行錯誤してみたけど無理だった。

(できた!って人いたら教えて欲しい)


あとがき

わいA「Node.jsはcommonJSes moduletypescriptやら

外部ファイルを読み込みたいだけなのに、書き方がたくさんあって混乱するんや」

わいB「比較的どんな言語でも"C/C++"ならどうか?

と置き換えて考えればある程度いけるんやけどな」

わいA「Node.jsのrequireC/C++でいうところの何になるんや」

わいB「バシッっと置き換わるものがなくてもやもやするよな」

わいB「exportsは外部リンケージ(extern)

グローバルにletとかで定義した変数は内部リンケージ(static)

と考えてよさそうやん?」

わいA「禿同」

わいA「問題はrequireや」

わいB「Cのincludeじゃね?」

わいA「そう思わせておいての、そうじゃないやつやん?」

わいB「せやなぁ、そもそもincludeってマクロやしな」

わいA「外部ファイルを取り込む的なニュアンスは同じやけど

根本的にNode.jsのrequireとは別物にしか見えないやで」

わいB「禿同、というわけで今回いろいろ試したわけやし、一応答えを見つけたやん」

わいB「requireはシングルトンをつくる関数やって」

わいA「ただの関数だったか」

わいB「ただの関数やったんや」

わいA「引数与えて、戻り値もあって」

わいA「確かに関数やな」

わいB「せや、関数や」

わいA「なんだぁ、関数だったか」

めでたしめでたし。