在介绍import()之前我们先来了解下export
和import
在JavaScript模块中,我们可以使用export
和import
来导出和导入变量、函数和类。
export
用于在模块中定义可以共享给其他模块的变量、函数或类。这些可以通过import
在其他模块中导入并使用。
以下是示例:
在module1.js
中:
export var obj = { name: 'keith' }; // 直接输出
export function sayHi(name) {
console.log('hi,' + name);
}
在module2.js
中:
import { obj, sayHi } from './module1.js'; // 导入module1.js中的obj和sayHi
console.log(obj.name); // 输出:"keith"
sayHi('John'); // 输出:"hi,John"
在这个例子中,module1.js
导出了变量obj
和函数sayHi
,然后我们在module2.js
中通过import
语句导入了这两个导出。之后,我们就可以在module2.js
中使用这两个导出的内容了。
请注意,一个模块只能有一个默认导出(export default)。比如:
export default obj; // 等同于 export { obj as default }
以上就是export和import的基本用法。
import命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(import命令叫做“连接” binding 其实更合适)。所以,下面的代码会报错。
// 报错
if (x === 2) {
import MyModual from './myModual';
}
上面代码中,引擎处理import语句是在编译时,这时不会去分析或执行if语句,所以import语句放在if代码块之中毫无意义,因此会报句法错误,而不是执行时错误。也就是说,import和export命令只能在模块的顶层,不能在代码块之中(比如,在if代码块之中,或在函数之中)。
这样的设计,固然有利于编译器提高效率,但也导致无法在运行时加载模块。在语法上,条件加载就不可能实现。如果import命令要取代 Node 的require方法,这就形成了一个障碍。因为require是运行时加载模块,import命令无法取代require的动态加载功能。
const path = './' + fileName;
const myModual = require(path);
上面的语句就是动态加载,require到底加载哪一个模块,只有运行时才知道。import命令做不到这一点。
ES2020提案 引入import()函数,支持动态加载模块。
import(specifier)
上面代码中,import函数的参数specifier,指定所要加载的模块的位置。import命令能够接受什么参数,import()函数就能接受什么参数,两者区别主要是后者为动态加载。
import()返回一个 Promise 对象。下面是一个例子。
const main = document.querySelector('main');
import(`./section-modules/${someVariable}.js`)
.then(module => {
module.loadPageInto(main);
})
.catch(err => {
main.textContent = err.message;
});
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,import()函数与所加载的模块没有静态连接关系,这点也是与import语句不相同。import()类似于 Node.js 的require()方法,区别主要是前者是异步加载,后者是同步加载。
由于import()返回 Promise 对象,所以需要使用then()方法指定处理函数。考虑到代码的清晰,更推荐使用await命令。
async function renderWidget() {
const container = document.getElementById('widget');
if (container !== null) {
// 等同于
// import("./widget").then(widget => {
// widget.render(container);
// });
const widget = await import('./widget.js');
widget.render(container);
}
}
renderWidget();
上面示例中,await命令后面就是使用import(),对比then()的写法明显更简洁易读。