问题描述
在JavaScript中,是否有类似CSS @import的语句,使之能够在JavaScript文件中引入其他JavaScript文件?
解决方案
在老版本的JavaScript文件中,不存在import
,include
和require
,所以针对这一问题出现了许多解决方案。
自从ES6诞生以来,JavaScript就有了标准的模块方案,大多数现代浏览器都支持这个方案。
Node.js中的ES6模块
Node.js从8.5版本已经开始支持ES6模块了,但需要启用--experimental-modules
标志,所有的文件也必须以.mjs
结尾。
// module.mjs
export function hello() {
return "Hello";
}
// main.mjs
import { hello } from 'module'; // 或者 './module'
let val = hello(); // val 为 "Hello";
浏览器中的ES6模块
Safari 10.1、Chrome 61、Firefox 60和Edge 16等版本的浏览器中都可以直接使用ES6模块语法了,不需要借助webpack之类的工具,你可以在caniuse中查找相关的兼容性。
<script type="module">
import { hello } from './hello.mjs';
hello('world');
</script>
// hello.mjs
export function hello(text) {
const div = document.createElement('div');
div.textContent = `Hello ${text}`;
document.body.appendChild(div);
}
在浏览器中进行动态导入
动态引入可以让脚本在需要的时候再进行加载:
<script type="module">
import('hello.mjs').then(module => {
module.hello('world');
});
</script>
Node.js require
module.exports/require在Node.js中依然是使用的最为广泛的模块导入机制。
// mymodule.js
module.exports = {
hello: function() {
return "Hello";
}
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val 为 "Hello"
另外,在浏览器中还有一些不需要预处理的模块导入机制。
AJAX加载
你可以使用AJAX加载脚本,然是使用eval
来执行脚本。但是,这种做法受限于浏览器的同源策略,并且eval
存在许多问题。
Fetch加载
你可以使用Fetch动态导入一些脚本,它返回一个promise对象,所以你可以控制脚本的加载顺序,下面的代码Fetch Inject库来加载脚本:
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方法实现了脚本加载:
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
动态导入脚本
你可以在HTML页面上,插入<script>
标签,以此实现脚本的动态导入。
这种方法不受同源策略的限制,并且浏览器自己会执行代码。
下面是一个例子:
function dynamicallyLoadScript(url) {
var script = document.createElement("script"); // 创建一个`script`节点
script.src = url; // 设置src属性
document.head.appendChild(script); // 将节点添加到页面上
}
上面的函数将会添加一个<script>
标签到页面上,我们将要导入的脚本地址作为参数传入到函数中。