javascriptの循環参照、circular dependencies。TypeError

by codechord. 0 Comments

  • このエントリーをはてなブックマークに追加
  • このエントリーをはてなブックマークに追加
Staircase Spiral Architecture  - stokpic / Pixabay

stokpic / Pixabay

javascriptを書いていて、requireの書き方で、ちょっとハマったのでメモ。

次のような要件を実装していくとします。

  • 子要素を生成することができるclass Person{}をつくる。
  • 要素を生成する機能は、class外に別途factory()メソッドを用意する。
  • Personにはchild()関数があり、factory()を実行して、子要素を作れる。

この仕組みを1ファイルですべて記述すると成功するのだけど、
ファイルを分割して、双方の関数をお互いがrequireしあうようにすると、
書き方によっては、そんな関数無いですよ!?と怒られます。

TypeError: factory is not a function

では。そのコードを紹介します。


動かないコード

factory.js

const {Person} = require("./Person");

function factory(){
  return new Person();
}

module.exports = {
  factory
};

Person.js

const {factory} = require("./factory");

class Person{
  constructor() {}
  say(){
    return "hello";
  }
  child(){
    return factory(); // ←このfactory()がundefinedだと怒られます。
  }
}
module.exports = {
  Person
};

 

const {factory} = require("./factory");
const parent = factory()
parent.say() // "hello"
parent.child().say() // "helloとでてほしい"
parent.child().child().say() // "helloとでてほしい"

Circular dependencies

なぜエラーになるかという所なのだけど、

  1. requireを記述した1行目で、require先のファイルが読み込まれる。
  2. require先のファイルが読み込み終わるまでは、require元のファイルの2行目以降が評価されない。
  3. で、require先の1行目でも、require元のファイルをrequireしているので、
  4. requireの無限ループされてしまう。

このことを、循環参照だったり、circular dependenciesだったり呼ばれるみたい。

では、どのようにするか。まずは、訂正版のコード。
Person.js 訂正版

class Person{
  constructor() {}
  say(){
    return "hello";
  }
  child(){
    const {factory} = require("./factory");
    return factory() // ←このfactory()がundefinedだと怒られます。
  }
}
module.exports = {
  Person
};

違いは、1行目に書いていた、require()を、実際に使う直前(childメソッド内)に移動させています。

「requireはファイルの最初にしか記述してはいけない」と思い込んでいたのだけど、
そんなことはないみたいで、実行したい直前にrequireを使い評価させることで、循環参照を回避させることができるみたい。

今回紹介した以外にも、解決方法あるみたいで、こちらの記事に、かなり具体的に解説されていましたので、合わせて参照されることをおすすめします!

node.jsにおける循環参照に対処するための3つの方法 – Qiita

 


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA