はじめに
- 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「なんだぁ、関数だったか」
めでたしめでたし。