DataWizardess 2026-02-27 01:40 采纳率: 98.9%
浏览 0
已采纳

`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'`,便于早期发现导出异常。
  • 写回答

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(); // 安全调用
    

    五、架构层:模块系统演进与迁移策略

    面对 "type": "module" 的强制约束,推荐渐进式迁移路径:

    graph LR A[现有 CommonJS 项目] --> B{是否已启用 “type”: “module”?} B -->|否| C[保留 require + module.exports] B -->|是| D[统一改用 import/export] D --> E[通过 dynamic import\(\) 加载 CommonJS 模块] E --> F[使用 createRequire\(\) 兼容旧模块]

    六、工程层:自动化检测方案

    在 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 成为可发现、可测试、可版本化的第一公民。

    ```
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 2月28日
  • 创建了问题 2月27日