はじめに
- Node.jsの
requireの挙動がおかしい! - そういえば
requireの細かいところよくしらない - いろいろ試してみよう
- 試したことを書いておこう
要約
**これおかしいんちゃうんけ!どないなっとんねん!!** ↓(色々試す) **わいがおかしいだけやんけ!!どうかしてたわ!!**調べてみたら**「あたりまえやんけ」ってなることも
調べるまでは「あたりまえじゃない」**ってことですね。
とりあえずほんの少しrequireに詳しくなれるかもしれない記事です。
ファイルに直で書かれた処理はrequireされたときに一度だけ評価される
const hoge1 = require("./hoge");
const hoge2 = require("./hoge");
console.log("Hoge");
Hoge
requireを2回しているけど、Hogeは1回しか表示されない。
requireするたびに評価されたらどうしようと思ったけど
評価されなかった、よかった。
exports.xxxしたプロパティは共有されるのか
const hoge1 = require("./hoge");
const hoge2 = require("./hoge");
console.log(hoge1.a);
console.log(hoge2.a);
exports.a = 0;
0
0
index.jsに以下の1行を入れたらどうなるか
const hoge1 = require("./hoge");
const hoge2 = require("./hoge");
+ hoge1.a = 10;
console.log(hoge1.a);
console.log(hoge2.a);
10
10
hoge1.aを変えたらhoge2.aも変わった。
requireは同じ参照先を返してくるらしい。
requireしたファイルの中の処理が評価されるタイミングは?
const hoge = require('./hoge');
console.log(hoge.a);
const foo = require('./foo');
console.log("Hoge");
exports.a = 0;
console.log("Foo");
Hoge
0
Foo
requireしたタイミングで評価される。
ここらへんはインタプリタですなぁ。
fooの中でhogeの中身いじったら?
const hoge = require('./hoge');
console.log(hoge.a);
const foo = require('./foo');
+ console.log(hoge.a);
console.log("Foo");
+ const hoge = require('./hoge');
+ hoge.a = "Fooの中で書き換えてやったぜ";
Hoge
0
Foo
+ Fooの中で書き換えてやったぜ
requireは同じ参照を返すわけだから
foo.jsの中でhoge.aを書き換えたらindex.jsのhoge.aにも影響する。
当然である。
なんかシングルトンに見えてきた
実際の動きから見えてくる事実や推測
- 初めて
requireされた時に一度だけ中の処理が評価される - 2回目以降の
requireでは、1回目の時に評価されたモノ(インスタンス)の参照が戻ってくる。
すごくあれっぽいな
これって要するにシングルトンじゃないですか?
requireがシングルトンをつくる関数に見えてきました。
これが
const hoge1 = require("./hoge");
const hoge2 = require("./hoge");
こう見えてきた感じ(要するにhogeのinstanceがくるんやろって見えてる目)
const hoge1 = hoge.instance;
const hoge2 = hoge.instance;
まとめ
結局何が知りたかったのか
const a = require('hoge');
const b = require('hoge');
果たしてaとbは同じものになるのか?
いや、同じじゃないと困るでしょって話だし結果同じもの入ってました。
どうにか違うものが返せないかと試行錯誤してみたけど無理だった。
(できた!って人いたら教えて欲しい)
あとがき
わいA「Node.jsはcommonJSやes moduleやtypescriptやら
外部ファイルを読み込みたいだけなのに、書き方がたくさんあって混乱するんや」
わいB「比較的どんな言語でも"C/C++"ならどうか?
と置き換えて考えればある程度いけるんやけどな」
わいA「Node.jsのrequireはC/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「なんだぁ、関数だったか」
めでたしめでたし。