You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中类循环依赖导致TypeError: Page1 is not a constructor错误

循环引用导致的构造函数错误问题及解决方法

问题背景

你使用了如下类结构:

  • 根类BasePage
  • 两个继承自BasePage的子类Page1和Page2,二者互相引用并在方法中实例化对方

代码示例

BasePage.js

class BasePage {
    constructor() {
        this.root = "rootbase";
    }
}
module.exports = BasePage;

Page1.js

const Page2 = require('./page2')
const BasePage = require("./basePage")

class Page1 extends BasePage {
    constructor() {
        super();
        this.root = "root1";
    }
    open2() {
        global.plop = new Page2()
    }
}

module.exports = Page1;

Page2.js

const Page1 = require('./page1')
const BasePage = require("./basePage")

class Page2 extends BasePage {
    constructor() {
        super();
        this.root = "root2";
    }
    open1() {
        global.plop = new Page1()
    }
}

module.exports = Page2;

执行代码

global.plop = new BasePage();
global.plop = new Page1();
plop.open2();
plop.open1();

错误信息

Uncaught TypeError TypeError: Page1 is not a constructor
    at open1 (c:\Users\Amira\Projects\nodetemp\page2.js:10:17)
    at main (c:\Users\Amira\Projects\nodetemp\index.js:11:10)
    at <anonymous> (c:\Users\Amira\Projects\nodetemp\index.js:15:1)
    at Module._compile (internal/modules/cjs/loader:1159:14)
    at Module._extensions..js (internal/modules/cjs/loader:1213:10)
    at Module.load (internal/modules/cjs/loader:1037:32)
    at Module._load (internal/modules/cjs/loader:878:12)
    at executeUserEntryPoint (internal/modules/run_main:81:12)
    at <anonymous> (internal/main/run_main_module:23:47)

问题原因

这是CommonJS模块循环引用导致的问题:
Node.js加载CommonJS模块时,会优先加载模块的依赖。当Page1启动加载时,会触发Page2的加载;而Page2加载时又会反向加载Page1,此时Page1还未完成类的定义与导出,所以Page2拿到的Page1是一个未初始化的空对象,并非构造函数,调用new Page1()自然会报错。

解决方法

方法1:延迟加载模块

将模块的require语句从模块顶部移到方法内部,仅在方法执行时才加载目标模块,此时两个模块都已完成初始化:

修改后的Page1.js:

const BasePage = require("./basePage")

class Page1 extends BasePage {
    constructor() {
        super();
        this.root = "root1";
    }
    open2() {
        const Page2 = require('./page2');
        global.plop = new Page2()
    }
}

module.exports = Page1;

修改后的Page2.js:

const BasePage = require("./basePage")

class Page2 extends BasePage {
    constructor() {
        super();
        this.root = "root2";
    }
    open1() {
        const Page1 = require('./page1');
        global.plop = new Page1()
    }
}

module.exports = Page2;

方法2:重构代码消除循环依赖

提取公共逻辑到第三方模块,让Page1和Page2不再直接互相引用:

创建pageManager.js:

const Page1 = require('./page1');
const Page2 = require('./page2');

class PageManager {
    static openPage1() {
        global.plop = new Page1();
    }
    static openPage2() {
        global.plop = new Page2();
    }
}

module.exports = PageManager;

修改后的Page1.js:

const BasePage = require("./basePage")
const PageManager = require('./pageManager');

class Page1 extends BasePage {
    constructor() {
        super();
        this.root = "root1";
    }
    open2() {
        PageManager.openPage2();
    }
}

module.exports = Page1;

修改后的Page2.js:

const BasePage = require("./basePage")
const PageManager = require('./pageManager');

class Page2 extends BasePage {
    constructor() {
        super();
        this.root = "root2";
    }
    open1() {
        PageManager.openPage1();
    }
}

module.exports = Page2;

方法3:切换到ES模块

Node.js对ES模块(import/export)的循环引用处理更完善,你可以:

  1. 将文件扩展名改为.mjs
  2. 或者在package.json中添加"type": "module"
  3. 把require/module.exports替换为import/export

这种方式适合新项目,需要统一调整模块系统。

内容的提问来源于stack exchange,提问作者sarut0bi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:40:19