ES6 的模块化

历史上,JavaScript 一直没有自己的模块体系,直到 ES6 推出自己的模块化。它的实现不同于 CommonJS 和 AMD 的模块化,浏览器和服务器通用。但是目前浏览器和 nodejs 的支持有限。

下面简单记录 ES6 模块的特点

export

ES6 使用关键字 export 输出模块

直接输出变量

1
2
3
export let bar = 'bar'
export function foo () {}
export class animal {}

输出一组变量

1
2
3
4
5
6
const bar = 'bar'
function boo () {}
export {
bar,
foo
}

默认输出

1
export default function foo() {}

上述函数名 foo 可写可不写,其实 export default 输出的是匿名函数,import 时可以自定义函数名。加载后是获取不到函数名 foo 的。

输出重命名

1
2
3
4
5
6
const dinner = '晚餐吃什么?'
const dessert = 'cake'
export {
dinner as supper, // 把 dinner 以变量名 supper 输出
dessert as sweetie
}

错误的用法

export 只能使用标识符

1
2
3
4
5
const foo = 'foo'
export {
bar: 'bar',
foo: foo
}

export 不能写在块里面

1
2
3
4
if (true) {
export function foo() {}
}
// Uncaught SyntaxError: Unexpected token export

export default 的本质是把后面的值赋给 default 变量,所以后面不能接 let const var 语句

1
2
3
4
export default let bar = 'bar' // Uncaught SyntaxError: Unexpected token let
export default const foo = 'foo' // Uncaught SyntaxError: Unexpected token const
export default var baz = 'baz' // Uncaught SyntaxError: Unexpected token var
//

一个文件里可以有多个 export 只能有一个 export default

1
2
3
4
5
export default class animal {
constructor() {}
}
export default function foo () {}
// Uncaught SyntaxError: Duplicate export of 'default'

import

ES6 使用关键字 import 加载模块

加载指定

1
2
import { bar } from './moduleA.js'
console.log(bar)

加载默认

1
2
3
import foo from './moduleA.js'
// 等价于
import { default as foo } from './moduleA.js'

加载全部

1
2
import * as moduleA from './moduleA.js'
console.log(moduleA.bar)

加载重命名

1
2
// 把 supper 导入后保存在变量 dinner 里
import { supper as dinner } from './moduleA.js'

同时加载

1
2
// foo 对应 export default 变量
import foo, { bar } from './moduleA.js'

复合写法

moduleB
1
2
import { bar, foo } from './moduleA.js'
export { bar, foo }

如上需求可以复合写成如下

moduleB
1
2
3
4
5
6
7
8
// 导入导出指定
export { bar, foo } from './moduleA.js'
// 导出默认
export { default } from './moduleA.js'
// 整体导入导出,会忽略 export default
export * from './moduleA.js'
// 导入导出重命名
export { dinner as supper, default as dessert } from './moduleA.js'

错误的用法

import 不能写在块里面

1
2
3
4
if (true) {
import foo from './moduleA.js'
}
// Uncaught SyntaxError: Unexpected identifier

import 不能使用表单式或变量

1
2
const modulePath = './moduleA'
import { bar } from modulePath // Uncaught SyntaxError: Unexpected identifier

ES6 模块的特点

静态加载

CommonJS 和 AMD 模块,都是在代码运行时加载相应的模块。ES6 的模块编译时就完成了模块的加载,也叫静态加载。

严格模式

与 ES5 使用 ‘use strict’ 开启严格模式不同,ES6 模块自动采用严格模式。

动态绑定

通过 export 输出的模块内部变化时,同过 import 获取该模块可获得模块内部实时的值。与 CommonJS 对模块进行缓存不同

接口只读

通过 import 加载的模块,不能重新赋值,类似 const 声明的变量一样。

import 命令提升

import 命令有提升效果,应为它是编译的时就完成了模块加载。如下代码可正常执行

1
2
foo()
import foo from './moduleA.js'

import() 函数

由于 nodejs 的 require 加载模块是动态的,即在运行时加载模块。import 是静态加载,所以不能取代 require。因此有一个提案引入 import() 函数来实现动态加载模块。

import() 函数接受和 import 命令一样的参数,但该函数是异步加载,结果返回的是一个 Promise 对象。使用该函数很容易实现按需动态加载。

1
2
3
4
5
6
7
8
const modulePath = './moduleA.js'
if (true) {
import(modulePath).then(({ bar }) => {
console.log(bar)
}).catch(e => {
console.error(e)
})
}
The End
# module

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×