NodeJS ES模块项目中加载外部JS文件函数的正确方法
问题:NodeJS中通过eval加载外部JS文件函数报错"ReferenceError: sarasa2 is not defined"
我正在开发一款以网页为核心载体的机器人,动作代码需要在网页编写,由服务器端适时通过eval执行。少量代码还好维护,但大型项目就会变得困难。所以我想搭建测试环境,把代码纳入Git仓库,测试通过后再上传。
当前遇到的具体问题:在NodeJS模块项目的测试套件中,尝试加载外部JS文件(sarasa.js)中的sarasa2函数并运行,用fs读取文件内容后通过eval执行,却报错找不到该函数。想知道能不能实现运行该文件中的函数,以及正确的实现方式是什么?
sarasa.js 代码
function sarasa2(){ console.log( " aca toy!"); return true; }
测试代码
import { Test } from "../../myjsunit/testSuite.js"; import fs from 'fs'; class so_Test extends Test { test_load_and_run(){ let fname = "testsjs/micro/sarasa.js"; let code = fs.readFileSync( fname ).toString() ; eval( "("+code+")" ); let actual = sarasa2(); this.assertTrue( actual ); this.done(); } } export { so_Test }
报错信息
ReferenceError: sarasa2 is not defined
解决方案
1. 直接执行eval(最简单的修复)
你当前用eval("("+code+")")的写法,是把函数代码包裹成了一个函数表达式,执行后不会将sarasa2暴露到当前作用域,所以找不到该函数。直接去掉括号包裹,执行原始代码即可:
let code = fs.readFileSync( fname ).toString() ; eval(code); // 移除多余的括号包裹 let actual = sarasa2();
这样函数会被定义在当前作用域中,就能正常调用了。
2. 包裹成作用域容器避免污染(更安全)
如果担心直接eval会污染全局/当前作用域,可以把代码包裹成一个自执行函数,返回需要的函数:
const exports = eval(`(() => { ${code} return { sarasa2 } })()`); let actual = exports.sarasa2();
这种方式会把目标函数封装在一个对象里返回,既不会污染外部作用域,又能获取到需要的函数。
3. 改用Node.js模块化加载(推荐)
如果测试环境允许,直接把sarasa.js改成ES模块是最规范的做法,完全不需要用eval:
修改sarasa.js:
export function sarasa2(){ console.log( " aca toy!"); return true; }
测试代码中直接导入:
import { Test } from "../../myjsunit/testSuite.js"; import { sarasa2 } from "./testsjs/micro/sarasa.js"; class so_Test extends Test { test_load_and_run(){ let actual = sarasa2(); this.assertTrue( actual ); this.done(); } } export { so_Test }
这种方式符合Node.js的模块化规范,代码可维护性更高,也避免了eval带来的安全和调试问题。
内容的提问来源于stack exchange,提问作者RudyMartin
相关产品推荐
相关产品推荐

