Vanilla NodeJS中导入函数报错TypeError: toData is not a function
问题分析与解决方案
这个报错TypeError: toData is not a function大概率是循环依赖搞的鬼,我来给你拆解清楚:
为什么会出现这个问题?
你看你的代码里,index.js中用到了mainEvents.emit("format-export"),如果mainEvents是从sql-actions.js导入的(或者index.js还导入了sql-actions.js的其他内容),而sql-actions.js又反过来导入了index.js的pushToData函数,这就形成了模块循环引用。
在Node.js的CommonJS模块加载机制里,当两个模块互相导入时,其中一个模块会先被加载,但还没执行完所有代码就被另一个模块引用,此时它的module.exports还是初始的空对象——后续虽然会把pushToData赋值给module.exports,但sql-actions.js已经拿到了那个空对象,所以调用toData时就会报错“不是函数”。
怎么解决?
最优雅的方式是重构代码,打破循环依赖,把共享的资源抽成独立模块:
步骤1:抽离事件发射器到单独模块
新建一个eventEmitter.js文件,专门存放事件发射器:
const events = require("events"); module.exports = new events.EventEmitter();
步骤2:修改index.js使用独立的事件模块
把原来依赖mainEvents的地方改成从新模块导入:
const mainEvents = require("./eventEmitter"); // 你的pushToData函数保持不变 function pushToData(input, title) { data[title] = input; console.log(data); if (isDataFull()) { mainEvents.emit("format-export"); } } module.exports = pushToData;
步骤3:修改sql-actions.js的依赖
如果sql-actions.js里需要用到同一个事件发射器,也从eventEmitter.js导入,不再和index.js互相引用:
const mssql = require("mssql"); const events = require("events"); const tagList = require("./tag"); const toData = require("./index"); // 导入独立的事件发射器 const mainEvents = require("./eventEmitter"); const tagEvents = new events.EventEmitter(); // ... 其他代码保持不变
这样两个模块都依赖独立的eventEmitter.js,不再互相导入,循环依赖的问题就解决了。
额外排查点
如果不是循环依赖的问题,你可以再检查这两点:
- 确认
index.js的文件路径是否正确:sql-actions.js里的require("./index")是否指向正确的文件,有没有拼写错误或者路径层级问题。 - 确认
index.js里没有在module.exports = pushToData;之后再覆盖module.exports的内容(比如又赋值了一个对象),这会导致之前的函数导出被覆盖。
内容的提问来源于stack exchange,提问作者Chris Rutherford
相关产品推荐
相关产品推荐

