1、概述

在js的历史上一直没有模块(module)体系,无法将一个大程序拆分成相互依赖的小文件,再用简单的方法拼装起来,这对开发大型的、复杂的项目形成了巨大障碍。

在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,

而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

2、ES6 模块(module)的设计思想是什么?

那就是尽量的静态化,使得编译时就能确定依赖关系

3、CommonJS模块 和 ES6 模块比较

看两段代码

  1. // 导出 node 文件系统的几个方法
  2. let {stat,exists,readFile} = require('fs');注意:这段代码实际上是加载了整个 fs 模块。这种加载方式称为“运行时加载”,因为只有运行时才能得到这个对象。导致完全没办法在编译时做“静态优化”。
  3. // ES6 模块
  4. import {stat,exists,readFile} from 'fs'注意:这段代码只导出了三个方法,其他的方法没有加载。这种方式称为“编译时加载”,ES6可以在编译时就完成模块加载,效率要比CommonJS模块的加载方式高。

4、模块功能命令之 export 和 import。

模块功能主要有两个命令构成:export 和 import。 export 命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

export命令

一个js文件就是一个模块,该文件内部的所有变量,外部无法获取,如果你希望外部能够读取模块内部某个变量,就必须使用export关键字输出该变量。

输出变量:

  1. //eg:对外部输出三个变量----》声明后输出// js 文件内部
  2. export var name = 'zjl'
  3. export var age = 18
  4. export var gender = '男'
  1. // eg:对外输出三个变量-----》先声明再输出 优先使用这种写法
  2. var name = 'zjl'
  3. var age = 18
  4. var gender = '男'
  5. export {name,age,gender}

输出函数:

  1. export function test(x,y){
  2. return x*y;
  3. }

export 输出的变量或函数都有自己的名字,我们也可以重命名:

  1. function test(){...}
  2. function test2(){....}
  3. function test3(){...}
  4. export {test as fun1,test2 as fun2,test3 as fun3}

注意:export 命令规定的是对外接口,接口名与模块内部变量之间,必须与模块的变量建立一一对应关系。(有种键值对的意思),

简单来说导出的变量他必须有一个值。

export 语句不能放在代码块内,如函数内,否则会报错。因为此做法使其无法做到静态化,违背了 ES6 模块的设计理念。

import 命令

通过 export 定义了模块的接口之后,我们可以通过import 命令加载这个模块。

载入模块方式:

  1. // 大括号内的变量名,必须跟 export 对外接口的变量名一致
  2. import {name,age,gender} from './XXX.js'// 重命名iport {name as username};

注意几个 import 关键点

①import 导入的值都是只读的,不允许修改输入的接口。

②可以修改导入的对象 ,可以修改导入对象的属性,但不推荐这样做,建议把导入的变量(不管是普通变量还是对象)都当做只读的。

③import…..from 中 from 后面的路径可以是绝路径也可以是相对路径。(导入本地文件时使用’./‘开头,导入下载库不需要加’./‘)

④js模块导入时可以省略后面 的 .js后缀。(在没有node环境下可能不可以省略)

⑤import 命令具有提升效果,它会把import命令提升到模块的头部,首先执行。

⑥执行同一个import命令多次,默认只会执行一次,不会执行多次

⑦在浏览器环境下(普通HTML文件中),script标签的类型必须是module才可以被导入

<script type="module"></script>

  1. import {name} from './XXX.js'
  2. import {name} from './XXX.js'
  3. //只会执行一次

⑧从同一个模块通过多条import加载不同变量,但它们对应的是同一个模块实例。import语句是 单例模式(Singleton)

  1. import {name} from './a.js'
  2. import {age} from 'a.js'
  3. // 单例模式

⑨不推荐 import 和 require 在同一个模块使用,因为他们的执行时期不一样,导致的结果可能就不一样。

目前在模块中使用 require 还需要 Babel 转换比较麻烦。

⑩整体加载模块

  1. import * as user from './a.js'
  2. // 导出 a 模块的所有值并命名为 user(一个对象)

5、模块功能命令之 export default

我们通过前面了解到 import 导入 export 对外接口 需要知道对外接口的准确名称,才能拿到对应的值,这样是比较麻烦的。为此ES6还提供了 export default 命令,

使用 export default 导出的值,import导入可以为这个导出值自定义名称。

  1. // 导出模块 a.js,导出一个匿名函数
  2. export default function (){...}
  3. //导入模块 b.js,
  4. import fun from './a.js'; // fun还可以为其他合法的名称

默认输出(export default)注意点

export default 只能使用一次,export可以使用多次

②后面不能跟变量声明语句

  1. export default var a=10; // 写法错误

③export default a 的含义就是jiang将变量 a 的值赋给变量 default,所以上面那种写法是错误的。

④ export 导出一定要指定对外接口 而 export default 不需要。

⑤export 和 export default 能一起使用。

6、export 和 import 的复合写法。

  1. export {name,age} from 'a.js' // 这种写法相当于转发了这两个接口,没有实际导入当前模块,当前模块不能直接使用这两个变量。
  2. // 可以写成两句,实际导入当前模块
  3. import {name,age} from 'a.js'
  4. export {name,age};