<script src="a.js"></script> <!-- 引入脚本 -->
<script type="module" src="b.js"></script> <!-- 引入模块 -->
ES6 模块标准有两部分:
声明性语法:用于导入和导出(导入是导出实体的只读视图)
可编程的 loader API:配置加载方式、有条件地加载
模块是单例的,即使一个模块被多次导入,它也只存在一个“实例”。
ES5 模块系统
CommonJS 模块:专为同步加载和服务器而设计,偏好单个导出、支持循环依赖
异步模块定义(AMD,如 RequireJS):专为异步加载和浏览器而设计
ES6 Module
对循环依赖的支持比 CommonJS 的要好(虽然支持,但尽量避免如此)
1. export 声明
export
不受 temporal dead zone 规则的约束。
两种类型:
named export:一个 module 可以有多个(多个命名导出,它们以名称区分)
default export:每个 module 只能有一个(单个默认导出,通常是一个 function 或 class)
可以同时使用两者,但通常最好分开使用。
named export
// 导出 name list
export { myFunction2, myVariable2 } // 不能是 empty object
// 支持 var, let, const, function, class)
export let myVariable = Math.sqrt(2)
export function myFunction() { }
// file-1 lib.js
export const sqrt = Math.sqrt
export function square(x) {
return x * x
}
export function diag(x, y) {
return sqrt(square(x) + square(y))
}
// file-2 main.js
// 可以分开导入(更推荐)
import { square, diag } from 'lib'
console.log(square(11))
console.log(diag(4, 3))
// 也可以导入完整的模块
import * as lib from 'lib'
console.log(lib.square(11))
console.log(lib.diag(4, 3))
default export
表示在 import
时可以随便起名字。
注意:此时导出的是变量的“值”(和导出变量的行为是不一样的),此时修改变量不会导致其它模块中引入的 default 值发生改变。
// 以下两行等价
export { myFunction as default }
export default myFunction
// 用 as 重新命名
export { variable1 as name1, variable2 as name2, ... nameN }
export { variable1 as "string name" } //
export { myFunction as "my-function" } // rename 成一个 not a valid identifier
// 导出单个的
export default function () { }
export default class { }
// 支持任何表达式
export default 1 + 1
re-export 或聚合
export { default as function1, function2 } from "bar.js"
// 等价于 import/export
import { default as function1, function2 } from "bar.js"
export { function1, function2 }
// 大多数 `import from` 语法都有对应的 `export from` 语法
export { default as DefaultExport } from "bar.js"
export { default, function2 } from "bar.js" // as 可省
2. import 声明
两种方式:
import
declaration:只能用于 modules 中,且只能在 top-level(不能在 block 或 function 里)
import
声明的四种形式:
// 1. named import
import { foo, bar } from "/modules/my-module.js"
import { myExport } from "/modules/my-module.js"
import { myExport as a } from "/modules/my-module.js"
// 2. default import
import myDefault from "/modules/my-module.js"
import { default as myDefault } from "/modules/my-module.js"
// 3. namespace import
import * as namespaceObject from "module-name"
// 注意:JavaScript 没有像 import * from "module-name" 这样的通配符导入
// 因为名称冲突的可能性很高
// 4. side effect import
// 这会运行模块的 global code,但并不会导入任何值
// 通常用于改变全局变量的 polyfill
import "/modules/my-module.js"
静态 import
声明用来导入 read-only live bindings(只读实时绑定),之所以叫 live bindings,是因为它们的值只能由 export 绑定的模块来更新,而 import 它的模块不能 re-assign。
尽管如此,任何持有导出对象的模块都可以改变该对象,并且所有其它导入相同值的模块都可以观察到修改后的值。还可以通过 module namespace object 来观察新值。
需要注意的是,import 与一般的赋值不同,import 后的变量只是改变了名字,它仍然与原来的变量是同一个,即便变量是非引用型的基本类型。
// a.js
export var a = 1
// index.js
import { a } from './a.js'
a = 3 // 会报错:Uncaught TypeError: Assignment to constant variable.