历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。
ES6中引入了模块化,针对模块化,我们需要知道:
- 如何定义模块
- 怎么引入并使用定义好的模块
模块功能主要由两个命令构成:export
和import
。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
1. 如何定义模块 (export)
创建modules.js(文件名字可以随便定义),定义变量,然后使用export关键字输出该变量(如下:)
// modules.js
export let a = 1;
export let b = 2;
export let c = 3;
export的写法,除了像上面这样,还有另外一种
// modules.js
let a = 1;
let b = 2;
let c = 3;
export {
a,
b,
c
}
export命令除了输出变量,还可以输出函数或类(class)
// modules.js
export function sum (x,y){
return x+y;
}
通常情况下,export输出的变量就是本来的名字,但是可以使用as
关键字重命名
// modules.js
let a = 1;
let b = 2;
let c = 3;
export {
a as aa
b as bb,
c as cc
}
总结:export 输出变量的写法
// modules.js
// 报错
export 1;
// 报错
var m = 1;
export m;
// 正确写法一
export var m = 1;
// 正确写法二
var m = 1;
export {m};
// 正确写法三
var n = 1;
export {n as m};
// 报错
function f() {}
export f;
// 正确
export function f() {};
// 正确
function f() {}
export {f};
2.如何引入并使用定义好的模块(import)
浏览器加载 ES6 模块,也使用<script>
标签,但是要加入type="module"
属性。
<script type="module" src="./foo.js"></script>
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
// main.js
import {a,b,c} from './modules.js'
// import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。如果只是模块名,不带有路径,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。
console.log(a,b,c)
上面代码的import命令,用于加载modules.js文件,并从中输入变量。import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(modules.js)对外接口的名称相同。
如果想为输入的变量重新取一个名字
,import命令要使用as关键字
,将输入的变量重命名。
import {a as aa ,b as bb ,c as cc} from './modules.js'
模块的整体加载:
// modules.js
export let a = 1;
export let b = 2;
// main.js
import * as foo from './modules.js'
console.log(foo.a) // 1
console.log(foo.b) // 2
export default 命令:
// modules.js
export default function foo() {
console.log('foo');
}
// 或者写成
function foo() {
console.log('foo');
}
export default foo;
// main.js
import foo from './modules.js'
foo() // 'foo'
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。
// 正确
export var a = 1;
// 正确
var a = 1;
export default a;
// 错误
export default var a = 1;
// 正确
export default 42;
// 报错
export 42;
如果想在一条import语句中,同时输入默认方法和其他接口,可以写成下面这样。
import _, { each, forEach } from 'lodash';
//对应上面代码的export语句如下。
export default function (obj) {
// ···
}
export function each(obj, iterator, context) {
// ···
}
export { each as forEach };
import()函数,(完成动态加载)
由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
// 报错
import { 'f' + 'oo' } from 'my_module';
// 报错
let module = 'my_module';
import { foo } from module;
// 报错
if (x === 1) {
import { foo } from 'module1';
} else {
import { foo } from 'module2';
}
所以引入import()
函数,完成动态加载。import()返回一个 Promise 对象。
import()类似于 Node 的require方法,区别主要是前者是异步加载,后者是同步加载。
import() 适用场合:
- 按需加载
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
- 条件加载
if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}
- 动态的模块路径
import(f())
.then(...);