在另一个JavaScript文件中引入JavaScript文件的方法

在另一个JavaScript文件中引入JavaScript文件的方法

技术背景

早期的JavaScript版本没有importincluderequire等功能,因此开发者们开发了许多不同的方法来解决在一个JavaScript文件中引入另一个JavaScript文件的问题。但自2015年(ES6)起,JavaScript有了ES6模块标准,可在Node.js中导入模块,且大多数现代浏览器也支持该标准。为兼容旧浏览器,还可使用如Webpack、Rollup等构建工具和Babel等转译工具。

实现步骤

ES6模块

Node.js中使用ES6模块

从Node.js v8.5开始,使用--experimental-modules标志可支持ES6模块,从Node.js v13.8.0开始无需该标志。要启用“ESM”(相对于Node.js之前的CommonJS风格模块系统“CJS”),可在package.json中使用"type": "module",或给文件使用.mjs扩展名。

使用package.json

1
2
3
{
"type": "module"
}

module.js文件:

1
2
3
export function hello() {
return "Hello";
}

main.js文件:

1
2
import { hello } from './module.js';
let val = hello(); // val is "Hello";

使用.mjs扩展名:
module.mjs文件:

1
2
3
export function hello() {
return "Hello";
}

main.mjs文件:

1
2
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";

浏览器中使用ECMAScript模块

自Safari 10.1、Chrome 61、Firefox 60和Edge 16起,浏览器支持直接加载ECMAScript模块(无需Webpack等工具)。

1
2
3
4
<script type="module">
import { hello } from './hello.mjs'; // Or the extension could be just `.js`
hello('world');
</script>

hello.mjs文件:

1
2
3
4
5
export function hello(text) {
const div = document.createElement('div');
div.textContent = `Hello ${text}`;
document.body.appendChild(div);
}

浏览器中的动态导入

动态导入允许脚本按需加载其他脚本:

1
2
3
4
5
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>

Node.js require

Node.js中仍广泛使用的旧CJS模块风格是module.exports/require系统。

mymodule.js文件:

1
2
3
4
5
module.exports = {
hello: function() {
return "Hello";
}
}

server.js文件:

1
2
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"

其他方法

AJAX加载

使用AJAX调用加载额外的脚本,然后使用eval运行它,但受JavaScript沙盒安全模型限制,且使用eval会带来安全问题。

Fetch加载

使用fetch调用加载一个或多个脚本,并使用Fetch Inject库控制脚本依赖的执行顺序:

1
2
3
4
5
fetchInject([
'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})

jQuery加载

使用jQuery的$.getScript方法加载脚本:

1
2
3
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});

动态脚本加载

在HTML中动态添加脚本标签:

1
2
3
4
5
function dynamicallyLoadScript(url) {
var script = document.createElement("script"); // create a script DOM node
script.src = url; // set its src to the provided URL
document.head.appendChild(script); // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}

检测脚本是否执行

由于现代浏览器异步加载脚本,直接使用上述方法加载脚本后,不能立即使用新加载的代码。可使用事件来运行回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function loadScript(url, callback)
{
// Adding the script tag to the head as suggested before
var head = document.head;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;

// Then bind the event to the callback function.
// There are several events for cross browser compatibility.
script.onreadystatechange = callback;
script.onload = callback;

// Fire the loading
head.appendChild(script);
}

var myPrettyCode = function() {
// Here, do whatever you want
};

loadScript("my_lovely_script.js", myPrettyCode);

源代码合并/预处理

许多开发者使用如Parcel、Webpack或Babel等构建/转译工具,以使用即将推出的JavaScript语法、为旧浏览器提供向后兼容性、合并文件、压缩代码、执行代码分割等。

RequireJS

RequireJS可提供依赖管理、更好的并发性,并避免重复加载脚本。

some-dependency.js文件:

1
2
3
4
5
6
define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {
//Your actual script goes here.
//The dependent scripts will be fetched if necessary.

return libraryObject; //For example, jQuery object
});

implementation.js文件:

1
2
3
4
5
require(['some-dependency'], function(dependency) {
//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});

核心代码

以下是一些核心代码示例:

ES6模块导入示例

1
2
3
4
5
6
7
8
// module.js
export function hello() {
return "Hello";
}

// main.js
import { hello } from './module.js';
let val = hello();

Node.js require示例

1
2
3
4
5
6
7
8
9
10
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}

// server.js
const myModule = require('./mymodule');
let val = myModule.hello();

动态脚本加载示例

1
2
3
4
5
function dynamicallyLoadScript(url) {
var script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
}

最佳实践

  • 优先使用ES6模块:如果项目支持,优先使用ES6模块标准,因为它是JavaScript的未来标准,且大多数现代浏览器和Node.js都支持。
  • 使用构建工具:对于需要兼容旧浏览器的项目,使用Webpack、Rollup等构建工具和Babel等转译工具,以确保代码的兼容性和性能。
  • 处理异步加载:在使用异步加载脚本时,确保使用回调函数或Promise来处理脚本加载完成后的操作,避免出现未定义错误。

常见问题

脚本未按预期加载

原因可能是异步加载导致脚本未及时加载完成。解决方法是使用回调函数或Promise来确保脚本加载完成后再执行相关操作。

浏览器兼容性问题

某些旧浏览器可能不支持ES6模块或其他现代加载方法。可使用构建工具和转译工具来解决兼容性问题。

安全问题

使用evalAJAX加载脚本时,要注意安全问题,避免执行恶意代码。尽量使用官方推荐的加载方法。


在另一个JavaScript文件中引入JavaScript文件的方法
https://119291.xyz/posts/2025-05-07.how-to-include-a-javascript-file-in-another/
作者
ww
发布于
2025年5月7日
许可协议