javascript - 当两个文件相互需要时,Nodejs“不是构造函数”错误
问题描述
我需要将两个 js 对象(播放器和房间)放入彼此的文件中。但是当我这样做时,发生了意外错误。
应用程序.js:
const Player = require("./Player").Player
let player = new Player()
播放器.js:
const Room = require ("./Room").Room
let room = new Room()
const Player = function () {
let room = new Room()
}
exports.Player = Player
房间.js:
const Player = require("./Player").Player
let player = new Player()
const Room = function () {
}
exports.Room = Room
和错误:
/home/mosi/Github/test/Room.js:2
let player = new Player()
^
TypeError: Player is not a constructor
at Object.<anonymous> (/home/mosi/Github/test/Room.js:2:14)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Module.require (internal/modules/cjs/loader.js:692:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object.<anonymous> (/home/mosi/Github/test/Player.js:1:14)
at Module._compile (internal/modules/cjs/loader.js:778:30)
解决方案
因为它们相互依赖,所以你的模块是循环的;请参阅此处的 Node.js 文档。正如他们所说,“需要仔细规划才能使循环模块依赖项在应用程序中正常工作。” :-)
如果您可以避免在一个循环中使用模块,那通常是最好的。
使用 ESM,您所要做的“全部”就是不在Player
orRoom
的顶层使用Player.js
or Room.js
,但是对于您正在使用的 CJS 模块,您还必须做更多的事情。我不是在 CJS 模块中整理循环的专家,但我认为您需要做的主要事情是不要尝试立即获取Player
或Room
导出。让模块先完成加载。例如:
app.js
:
const Player = require("./Player").Player;
let player = new Player();
Player.js
:
// Import the module exports object, but don't grab its `Room` property yet
const RoomMod = require ("./Room");
// Don't do this at the top level: let room = new Room()
const Player = function () {
// Now it's safe to use the `Room` property
let room = new RoomMod.Room();
};
exports.Player = Player;
Room.js
:
// Get the module exports object, but don't try to get the `Player` property yet
const PlayerMod = require("./Player");
// Don't do this at the top level: let player = new Player()
const Room = function () {
};
exports.Room = Room;
对于它的价值,如果您使用 ESM(JavaScript 标准模块),您不必只导入模块,然后再使用属性,因为使用 ESM,导入的绑定是实时的。因此,尽管您仍然必须避免在 and 的顶层使用and ,但Player
您可以在不需要模块命名空间对象(CJS 导出对象的 ESM 等效项)的情况下导入它们:Room
Room.js
Player.js
app.js
:
import { Player } from "./Player.js";
let player = new Player();
Player.js
:
import { Room } from "./Room.js";
export const Player = function () {
let room = new Room()
};
Room.js
:
import { Player } from "./Player.js";
export const Room = function () {
};
推荐阅读
- svelte - 如何将 .js 文件添加到 Svelte REPL?
- node.js - VS 2019 社区中的 typescript 构建选项在哪里?
- .net-core - nuget 包无法在 VS 2019 中下载
- php - 按期分期付款 - PHP
- angular - Chrome 扩展内容脚本中的 Angular 元素
- reactjs - formik 表单中的 useFormik 是什么类型?
- ruby - Sinatra 根据请求安全地设置时区
- java - 如何找到在 Java 程序中创建的对象的数量?
- sql - 与贷款表的正确关系?
- php - 根据 WooCommerce 中的成本更改运输方式标签名称