`require('./script').run is not a function` 错误原因及修复方法?
`require('./script').run is not a function` 是 Node.js 中常见运行时错误,核心原因在于被引入的模块(`./script.js`)未正确导出 `run` 函数。典型场景包括:① 脚本使用 `module.exports = ...` 但赋值了非函数(如对象、字符串或未赋值);② 误用 `exports.run = ...` 却未同步设置 `module.exports = exports`;③ ES 模块语法(`export function run() {...}`)混用 `require()`(Node 默认不支持,需启用 `"type": "module"` 或改用 `import`);④ 文件路径错误导致 `require()` 返回 `undefined`,进而调用 `.run` 报错。修复方法:检查 `script.js` 是否含 `module.exports.run = function() {...}` 或 `module.exports = { run: function() {...} }`;确认文件存在且路径无拼写错误;若为 ES 模块,统一使用 `import` 语法并配置 `package.json` 的 `"type": "module"`。建议添加防御性判断:`typeof require('./script').run === 'function'`,便于早期发现导出异常。
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
1条回答 默认 最新
The Smurf 2026-02-27 01:41关注```html一、现象层:错误表征与上下文定位
当 Node.js 运行时抛出
require('./script').run is not a function,本质是属性访问链断裂——require()返回值不具备可调用的run属性。该错误不发生在模块加载阶段(无 SyntaxError),而是在执行期动态求值时触发,属典型的「运行时契约违约」。需立即区分:是模块导出失当?路径解析失败?还是模块系统语义冲突?二、诊断层:四维归因模型
依据 Node.js 模块生命周期与 CommonJS/ESM 双规范共存现实,构建如下归因矩阵:
维度 典型表现 检测命令 ① 导出形态错配 module.exports = { version: '1.0' }(无 run)console.log(require('./script'))② exports 与 module.exports 分离 exports.run = () => {}但未设module.exports = exportsrequire('./script') === require('./script').exports→ false③ ESM/CommonJS 混用 export function run(){}+require()(Node v14+ 默认拒绝)node --experimental-modules -e "import('./script.js')"④ 路径解析失效 require('./script')返回{}或undefinedrequire.resolve('./script')抛错即路径不存在三、根因层:CommonJS 导出机制深度解析
Node.js 的
require()始终返回module.exports对象。若仅写exports.run = fn,实际是向module.exports的浅拷贝对象赋值,而module.exports本身仍为初始空对象{}。唯有显式赋值module.exports = { run }或module.exports.run = fn才能确保导出契约成立。此为五年以上开发者亦常忽略的底层语义陷阱。四、验证层:防御性编程实践
const script = require('./script'); if (typeof script.run !== 'function') { throw new TypeError( `Expected ./script.js to export a 'run' function, ` + `but got ${typeof script.run}: ${util.inspect(script, { depth: 1 })}` ); } script.run(); // 安全调用五、架构层:模块系统演进与迁移策略
面对
graph LR A[现有 CommonJS 项目] --> B{是否已启用 “type”: “module”?} B -->|否| C[保留 require + module.exports] B -->|是| D[统一改用 import/export] D --> E[通过 dynamic import\(\) 加载 CommonJS 模块] E --> F[使用 createRequire\(\) 兼容旧模块]"type": "module"的强制约束,推荐渐进式迁移路径:六、工程层:自动化检测方案
在 CI 流程中注入模块契约校验脚本:
- 利用
node -p "require('./script').run"验证可调用性 - 通过
eslint-plugin-node规则node/no-missing-require检测路径 - 在
package.json中定义"exports"字段声明公共接口 - 使用 TypeScript 的
declare module为 JS 模块补全类型契约
七、认知层:超越语法的模块设计哲学
该错误折射出更深层的工程问题:模块接口未被当作契约(Contract)来管理。理想状态应是「导出即 API,导入即承诺」。建议在
```script.js头部添加 JSDoc 注释:/** @module script */,并配合
/** @function run @returns {Promise<void>} */jsdoc工具生成接口文档,使run成为可发现、可测试、可版本化的第一公民。本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报- 利用