ES6Module

185 阅读3分钟

ES6模块概述

在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,
成为浏览器和服务器通用的模块解决方案。

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,
都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。

模块标签及定义

<script type="module"> 
 // 模块代码
</script> 
<script type="module" src="path/to/myModule.js"></script>
带有type="nodule"属性的<script>标签,会告诉浏览器相关代码作为模块执行。

index.js文件
console.log(1)

index.html
<script src="./index.js" type="module"></script>
<script>
    console.log(2)
</script>
执行结果 2 1
模块会像<script defer>加载的脚本一样按顺序执行。解析到<script 
type="module">标签后会立即下载模块文件,但执行会延迟到文档解析完成。

<script src="./index.js" type="module"></script>
<script src="./index.js" type="module"></script>
<script>
    console.log(2)
</script>
执行结果 2 1
同一个模块无论在同一个页面被加载多少次,也不管是怎么加载的,都只执行一次。

export命令

//export 关键字用于声明一个值为命名导出。导出语句必须在模块顶级,不能嵌套在某个块中
// 允许
export ... 
// 不允许
if (condition) { 
 export ... 
} 
export const foo = 'foo'

//导出值对模块内部没有直接影响,,因此 export 语句与导出值的相对位置或者export 关键字在模块中出现的顺序没有限制。

// 允许,但应该避免
export {bar}
const bar = 'bar'
//导出时提供别名
export {bar as myBar}

//默认导出
export default {
    bar
}

//命名导出和默认导出不会冲突,所以 ES6 支持在一个模块中同时定义这两种导出:

// 会导致错误的不同形式:
// 行内默认导出中不能出现变量声明
export default const foo = 'bar'; 
// 只有标识符可以出现在 export 子句中
export { 123 as foo } 
// 别名只能在 export 子句中出现
export const foo = 'foo' as myFoo;

import命令

import {foo,myBar} from './moduleA.js'
console.log('foo',foo)//foo
console.log('myBar',myBar)//bar
import a from './moduleA.js'
console.log(a) 

//重命名需要使用as关键字
//import命令输入的变量都是只读的 如果是一个对象,改写对象的属性是允许的
import { firstName as name, lastName, year } from './moduleB.js';
console.log(name, lastName, year)

//模块标识符可以是相对于当前模块的相对路径,也可以是指向模块文件的绝对路径。它必须是纯字符串,不能是动态计算的结果。例如,不能是拼接的字符串。 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语句,那么只会执行一次,而不会执行多次。

模块转移导出

模块导入的值可以直接通过管道转移到导出。
如果想把一个模块的所有命名导出集中在一块,可以像下面这样在 bar.js 中使用*导出:
export * from './foo.js';

foo.js
export const baz = 'origin:foo'; 
bar.js
export * from './foo.js'; 
export const baz = 'origin:bar'; 
main.js
import { baz } from './bar.js'; 
console.log(baz); // origin:bar

类似地,外部模块的默认导出可以重用为当前模块的默认导出:
export { default } from './foo.js';

在重新导出时,还可以在导入模块修改命名或默认导出的角色。比如,可以像下面这样将命名导出
指定为默认导出:
export { foo as default } from './foo.js';