定义
在ES6之前,JavaScript是没有模块体系的。
所谓的模块体系,就是把一个大程序拆分成一个个有着一部分功能且互相依赖的小文件,然后再用简单的方法给拼接起来。而其他语言是有这项功能的,比如Ruby 的require、Python 的import,甚至就连 CSS 都有@import。
虽然没有模块体系,但社区还是制定了一些加载方案,主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。但CommonJS和AMD只能在运行时确定模块的依赖关系,以及输入和输出的变量。而ES6模块的设计思想是静态化,也就是在预编译的时候确定依赖关系和变量。一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。
使用方法
ES6通过export命令显式指定输出的代码,再通过import命令输入。
浏览器加载 ES6 模块,也使用 <script> 标签,不同的是要加入 type="module" 属性。
<script type="module">
import './text.js'
</script>
要注意的是,模块化需要放在服务器环境中,要不然会报错。调试时你可以这么做:
cnpm install http-server -g
进入该目录,执行
http-server
在浏览器打开 http://localhost:8080/
即可查看效果。
export
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
等同于
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};//大括号里是要输出的变量
注意:
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
// 报错
export 1;
// 报错
var m = 1;
export m;
正确写法:
// 写法一
export var m = 1;
// 写法二
var m = 1;
export {m};
// 写法三
var n = 1;
export {n as m};
除了对象,export命令还可以输出函数和类,用法和输出对象类似。
import
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
import { firstName, lastName, year } from './text.js';
其中大括号的变量名要与导入模块的对接口名称相同。
如果想重新取名,也可以使用as来完成:
import { lastName as surname } from './text.js';
注意:
1、import命令输入的变量都是只读的,因为它的本质是输入接口,所以不允许修改输入变量
import {a} from './xxx.js'
a = {}; // Syntax Error : 'a' is read-only;
而a的属性是可以修改的,但这样容易出现问题,所以建议还是不要修改输入变量的属性。
2、如果多次重复执行同一句import语句,只会执行一次。
3、如果需要整体加载,可以使用(*
)
import * as circle from './circle';
export default 命令
export default命令为模块指定默认输出。
//num.js
export default 1
export var a = 2
export var b = 3
import 1,{a,b} from './num.js'
可以看出,使用export default命令和使用export的区别就是export default命令输入时没有大括号。
总结
ES6模块化有以下限制:
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用with语句
- 不能对只读属性赋值,否则报错
- 不能使用前缀 0 表示八进制数,否则报错
- 不能删除不可删除的属性,否则报错
- 不能删除变量delete prop,会报错,只能删除属性delete - global[prop]
- eval不会在它的外层作用域引入变量
- eval和arguments不能被重新赋值
- arguments不会自动反映函数参数的变化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局对象
- 不能使用fn.caller和fn.arguments获取函数调用的堆栈
- 增加了保留字(比如protected、static和interface)
优点
1.减少命名冲突
2.避免引入时的层层依赖
3.可以提升执行效率