问题描述
JavaScript 中是否有类似于 CSS 中的 @import
的东西,允许您将一个 JavaScript 文件包含在另一个 JavaScript 文件中?
旧版本的 JavaScript 没有导入、包含或要求,因此已经开发了许多不同的方法来解决这个问题.
但自 2015 年 (ES6) 以来,JavaScript 已采用 ES6 模块 标准来导入模块Node.js,大多数现代浏览器也支持.
为了与旧浏览器兼容,构建工具,如 Webpack 和 Rollup 和/或诸如 Babel 之类的转译工具.
ES6 模块
ECMAScript (ES6) 模块从 v8.5 开始被支持在 Node.js 中,具有--experimental-modules
标志,并且至少 Node.js v13.8.0 没有标志.要启用ESM"(相对于 Node.js 以前的 CommonJS 样式模块系统 ["CJS"]),您可以在 package.json
"type": "module"> 或给文件扩展名 .mjs
.(同样,如果您的默认值为 ESM,则使用 Node.js 以前的 CJS 模块编写的模块可以命名为 .cjs
.)
使用package.json
:
{类型":模块"}
然后module.js
:
导出函数 hello() {return "你好";}
然后main.js
:
import { hello } from './module.js';让 val = hello();//val 是你好";
使用 .mjs
,您将拥有 module.mjs
:
导出函数hello() {return "你好";}
然后main.mjs
:
import { hello } from './module.mjs';让 val = hello();//val 是你好";
浏览器中的 ECMAScript 模块
浏览器支持直接加载 ECMAScript 模块(不需要像 Webpack 这样的工具)自从 Safari 10.1、Chrome 61、Firefox 60 和 Edge 16.在 caniuse.无需使用 Node.js 的 .mjs
扩展名;浏览器完全忽略模块/脚本上的文件扩展名.
//hello.mjs -- 或者它可以是简单的 `hello.js`导出函数你好(文本){const div = document.createElement('div');div.textContent = `你好 ${text}`;document.body.appendChild(div);}
在 https://jakearchibald.com/2017/es-modules-阅读更多信息浏览器内/
浏览器中的动态导入
动态导入让脚本根据需要加载其他脚本:
在 https://developers.google.com/web 上阅读更多信息/updates/2017/11/dynamic-import
Node.js 需要
在 Node.js 中仍然广泛使用的旧 CJS 模块样式是 module.exports
/需要
系统.
//mymodule.js模块.出口 = {你好:函数(){return "你好";}}
//server.jsconst myModule = require('./mymodule');让 val = myModule.hello();//val 是你好"
JavaScript 还有其他方法可以在不需要预处理的浏览器中包含外部 JavaScript 内容.
AJAX 加载
您可以使用 AJAX 调用加载额外的脚本,然后使用 eval
来运行它.这是最直接的方法,但由于 JavaScript 沙箱安全模型,它仅限于您的域.使用 eval
也为漏洞、黑客和安全问题打开了大门.
获取加载
与动态导入一样,您可以通过 fetch
调用加载一个或多个脚本,使用承诺控制脚本依赖项的执行顺序,使用 Fetch Inject 库:
fetchInject(['https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js']).then(() => {console.log(`在不到 ${moment().endOf('year').fromNow(true)}` 内完成})
jQuery 加载
$.getScript("my_lovely_script.js", function() {alert("脚本已加载但不一定执行.");});
动态脚本加载
您可以将带有脚本 URL 的脚本标记添加到 HTML 中.为了避免 jQuery 的开销,这是一个理想的解决方案.
脚本甚至可以驻留在不同的服务器上.此外,浏览器会评估代码. 标签可以注入到网页
中,也可以插入到结束
之前> 标签.
这是一个如何工作的例子:
function dynamicLoadScript(url) {var script = document.createElement("script");//创建一个脚本 DOM 节点脚本.src = url;//将其 src 设置为提供的 URLdocument.head.appendChild(script);//将其添加到页面头部部分的末尾(可以将 'head' 更改为 'body' 以将其添加到正文部分的末尾)}
这个函数会在页面head部分的末尾添加一个新的标签,其中
src
属性被设置为URL给函数作为第一个参数.
这两种解决方案都在 JavaScript 疯狂:动态脚本加载中进行了讨论和说明.>
检测脚本何时执行
现在,您必须了解一个大问题.这样做意味着您远程加载代码.现代 Web 浏览器将加载文件并继续执行您当前的脚本,因为它们异步加载所有内容以提高性能.(这适用于 jQuery 方法和手动动态脚本加载方法.)
这意味着如果你直接使用这些技巧,你将无法在你要求加载后的下一行使用新加载的代码,因为它仍然会加载.
例如:my_lovely_script.js
包含 MySuperObject
:
var js = document.createElement("script");js.type = "文本/javascript";js.src = jsFilePath;document.body.appendChild(js);var s = new MySuperObject();错误:MySuperObject 未定义
然后您按 重新加载页面.它有效!令人困惑...
那怎么办?
好吧,您可以使用作者在我给您的链接中建议的 hack.综上所述,对于赶时间的人来说,他使用一个事件,在脚本加载时运行一个回调函数.所以你可以把所有使用远程库的代码放在回调函数中.例如:
function loadScript(url, callback){//按照之前的建议将脚本标签添加到头部var head = document.head;var script = document.createElement('script');script.type = '文本/javascript';脚本.src = url;//然后将事件绑定到回调函数.//跨浏览器兼容性有几个事件.script.onreadystatechange = 回调;script.onload = 回调;//触发加载head.appendChild(脚本);}
然后,在将脚本加载到 lambda 函数后编写要使用的代码:
var myPrettyCode = function() {//在这里,做你想做的};
然后你运行所有:
loadScript("my_lovely_script.js", myPrettyCode);
请注意,脚本可能会在 DOM 加载之后或之前执行,具体取决于浏览器以及您是否包含 script.async = false;
行.有一篇关于 Javascript 加载的优秀文章对此进行了讨论.
源代码合并/预处理
正如在这个答案的顶部提到的,许多开发人员在他们的项目中使用构建/转换工具,如 Parcel、Webpack 或 Babel,允许他们使用即将到来的 JavaScript 语法,为旧浏览器提供向后兼容性,合并文件,缩小,执行代码拆分等
Is there something in JavaScript similar to @import
in CSS that allows you to include a JavaScript file inside another JavaScript file?
The old versions of JavaScript had no import, include, or require, so many different approaches to this problem have been developed.
But since 2015 (ES6), JavaScript has had the ES6 modules standard to import modules in Node.js, which is also supported by most modern browsers.
For compatibility with older browsers, build tools like Webpack and Rollup and/or transpilation tools like Babel can be used.
ES6 Modules
ECMAScript (ES6) modules have been supported in Node.js since v8.5, with the --experimental-modules
flag, and since at least Node.js v13.8.0 without the flag. To enable "ESM" (vs. Node.js's previous CommonJS-style module system ["CJS"]) you either use "type": "module"
in package.json
or give the files the extension .mjs
. (Similarly, modules written with Node.js's previous CJS module can be named .cjs
if your default is ESM.)
Using package.json
:
{
"type": "module"
}
Then module.js
:
export function hello() {
return "Hello";
}
Then main.js
:
import { hello } from './module.js';
let val = hello(); // val is "Hello";
Using .mjs
, you'd have module.mjs
:
export function hello() {
return "Hello";
}
Then main.mjs
:
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";
ECMAScript modules in browsers
Browsers have had support for loading ECMAScript modules directly (no tools like Webpack required) since Safari 10.1, Chrome 61, Firefox 60, and Edge 16. Check the current support at caniuse. There is no need to use Node.js' .mjs
extension; browsers completely ignore file extensions on modules/scripts.
<script type="module">
import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
hello('world');
</script>
// hello.mjs -- or it could be simply `hello.js`
export function hello(text) {
const div = document.createElement('div');
div.textContent = `Hello ${text}`;
document.body.appendChild(div);
}
Read more at https://jakearchibald.com/2017/es-modules-in-browsers/
Dynamic imports in browsers
Dynamic imports let the script load other scripts as needed:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
Read more at https://developers.google.com/web/updates/2017/11/dynamic-import
Node.js require
The older CJS module style, still widely used in Node.js, is the module.exports
/require
system.
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"
There are other ways for JavaScript to include external JavaScript contents in browsers that do not require preprocessing.
AJAX Loading
You could load an additional script with an AJAX call and then use eval
to run it. This is the most straightforward way, but it is limited to your domain because of the JavaScript sandbox security model. Using eval
also opens the door to bugs, hacks and security issues.
Fetch Loading
Like Dynamic Imports you can load one or many scripts with a fetch
call using promises to control order of execution for script dependencies using the Fetch Inject library:
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 Loading
The jQuery library provides loading functionality in one line:
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
Dynamic Script Loading
You could add a script tag with the script URL into the HTML. To avoid the overhead of jQuery, this is an ideal solution.
The script can even reside on a different server. Furthermore, the browser evaluates the code. The <script>
tag can be injected into either the web page <head>
, or inserted just before the closing </body>
tag.
Here is an example of how this could work:
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)
}
This function will add a new <script>
tag to the end of the head section of the page, where the src
attribute is set to the URL which is given to the function as the first parameter.
Both of these solutions are discussed and illustrated in JavaScript Madness: Dynamic Script Loading.
Detecting when the script has been executed
Now, there is a big issue you must know about. Doing that implies that you remotely load the code. Modern web browsers will load the file and keep executing your current script because they load everything asynchronously to improve performance. (This applies to both the jQuery method and the manual dynamic script loading method.)
It means that if you use these tricks directly, you won't be able to use your newly loaded code the next line after you asked it to be loaded, because it will be still loading.
For example: my_lovely_script.js
contains MySuperObject
:
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
var s = new MySuperObject();
Error : MySuperObject is undefined
Then you reload the page hitting . And it works! Confusing...
So what to do about it ?
Well, you can use the hack the author suggests in the link I gave you. In summary, for people in a hurry, he uses an event to run a callback function when the script is loaded. So you can put all the code using the remote library in the callback function. For example:
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);
}
Then you write the code you want to use AFTER the script is loaded in a lambda function:
var myPrettyCode = function() {
// Here, do whatever you want
};
Then you run all that:
loadScript("my_lovely_script.js", myPrettyCode);
Note that the script may execute after the DOM has loaded, or before, depending on the browser and whether you included the line script.async = false;
. There's a great article on Javascript loading in general which discusses this.
Source Code Merge/Preprocessing
As mentioned at the top of this answer, many developers use build/transpilation tool(s) like Parcel, Webpack, or Babel in their projects, allowing them to use upcoming JavaScript syntax, provide backward compatibility for older browsers, combine files, minify, perform code splitting etc.
这篇关于如何在另一个 JavaScript 文件中包含一个 JavaScript 文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!