HOWTO · JavaScript
如何从另一个 JS 文件导入函数
了解如何使用浏览器脚本、ECMAScript 模块、Node.js CommonJS 或传统的 jQuery,从另一个 JavaScript 文件调用函数。
本页内容
要从另一个 JavaScript 文件调用函数,请根据环境选择共享方法:经典的 <script> 标签将函数公开为浏览器全局变量,ECMAScript 模块使用 export 和 import,Node.js CommonJS 使用 module.exports 和 require。下面的示例展示了如何连接这些文件以及每种方法的运行位置。
在浏览器中从另一个 JavaScript 文件调用函数
对于使用经典脚本的页面,在一个文件中定义函数,并在调用它的脚本之前加载该文件。经典脚本共享页面的全局作用域,因此第一个文件可以将函数附加到 window:
- 在
greeting.js中,编写window.showGreeting = function () { document.querySelector("#message").textContent = "Hello from greeting.js"; };。 - 在
app.js中,编写document.querySelector("#show").addEventListener("click", window.showGreeting);。
将这些文件保存在 index.html 旁边。此页面按所需顺序加载它们,并提供按钮和消息元素:
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Call a function from another file</title>
<p id="message">Click the button to show the message.</p>
<button id="show" type="button">Show greeting</button>
<script src="greeting.js"></script>
<script src="app.js"></script>
</html>
当按钮被点击时,app.js 中的处理程序会调用从 greeting.js 加载的函数。请将定义脚本放在前面;否则,页面可能会在 window.showGreeting 存在之前尝试注册处理程序。这个 html 代码块是浏览器页面示例,而不是运行时输出记录。
使用 ECMAScript 模块共享函数
当您希望使用显式导入而不是共享全局变量时,请使用 ECMAScript 模块。将这三个完整文件保存在同一目录中。第一个文件导出一个函数,第二个文件导入它并更新页面:
greeting.js:export function makeGreeting(name) { return \Hello, ${name}!`; }`app.js:import { makeGreeting } from "./greeting.js"; document.querySelector("#message").textContent = makeGreeting("Ada");
将此完整页面另存为 index.html,放在这些文件旁边。在模块运行之前,其消息元素已经存在:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Share a function with a module</title>
</head>
<body>
<p id="message">The greeting will appear here.</p>
<script type="module" src="app.js"></script>
</body>
</html>
保持相对导入路径与文件位置一致。浏览器以模块语义加载模块,不会将其中声明的内容放到 window 上。
请通过本地开发服务器以 HTTP 方式提供该页面;直接以 file: URL 打开它通常会阻止模块加载。这是浏览器的托管要求,而不是运行 Node.js 的要求。Node.js 也支持 ECMAScript 模块,并有其自己的包和文件扩展名规则。ECMAScript 模块导出语法对函数和其他值使用同样的 export 机制。
使用 CommonJS 在 Node.js 中导入函数
CommonJS 是 Node.js 传统的模块系统。模块可以将函数赋给 module.exports,另一个文件可以用 require 获取它。链接的 JavaScript import 与 require 的比较解释了这些模块系统之间的差异。
这个自包含的 Node.js 示例创建一个辅助文件,导入其函数并调用它。将代码保存为 main.cjs,并在安装了 Node.js 的终端中运行 node main.cjs:
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const folder = fs.mkdtempSync(path.join(os.tmpdir(), "function-demo-"));
try {
const helperPath = path.join(folder, "math.cjs");
fs.writeFileSync(helperPath, "module.exports = (a, b) => a + b;\n");
const add = require(helperPath);
console.log(`Result: ${add(5, 3)}`);
} finally {
fs.rmSync(folder, { recursive: true, force: true });
}
Result: 8
辅助文件导出一个函数,调用方将其作为 require 的返回值接收;最后的 console.log 调用使用这个返回的函数。.cjs 扩展名使辅助文件的 CommonJS 格式明确,即使周围项目使用 ECMAScript 模块也是如此。此示例是为 Node.js 编写的,不会在浏览器页面中运行。
使用 jQuery 加载 JavaScript 文件
jQuery 的 $.getScript() 可以按需加载脚本。这是已经使用 jQuery 的页面的一种传统替代方法;新代码通常使用浏览器模块或普通脚本标签会更清晰。在调用方之前加载 jQuery,并等待加载回调后再使用下载文件中的函数。
例如,mathUtils.js 可以使用 window.mathUtils = { add: (a, b) => a + b }; 公开一个浏览器全局变量。在页面中,先加载 jQuery,并使用回调在脚本加载后调用函数:
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script>
$.getScript("mathUtils.js")
.done(function () {
const result = window.mathUtils.add(5, 3);
$("body").append(`<p>Result: ${result}</p>`);
})
.fail(function () {
$("body").append("<p>The script could not be loaded.</p>");
});
</script>
请求是异步的,因此依赖 mathUtils 的代码应放在 .done() 内部(或其他完成处理程序中),而不是紧跟在 $.getScript() 之后。对于跨源 URL,jQuery 可以通过脚本元素加载脚本;浏览器通常不要求对此类脚本加载进行 CORS。跨源的 fetch() 或 XHR 请求则确实需要服务器用 CORS 允许。脚本加载仍可能被 Content Security Policy 等浏览器策略阻止,或者在 URL 无法访问时失败。有关其加载行为,请参阅 jQuery $.getScript() 文档。