ES6之前模块的加载方案有:CommonJS(服务器)和AMD(浏览器)两种,ES6中出现这个功能之后完全替代可前面两者。成为浏览器和服务器通用的模块解决方案。
ES6模块与CommonJS的差异
- CommonJS输出的是一个值得拷贝,ES6模块输出的是值的引用
- CommonJS输出的是一个拷贝,所有模块内部的变化无法影响其他模块。
- ES6模块加载的机制:只要遇到一个模块加载import就会生成一个只读的引用,等真正执行脚本的时候,再根据这个引用到被夹在的模块中取值,所以ES6模块是动态引用的,并不会缓存值
- CommonJS是运行时加载,ES6模块是编译时输出接口
- CommonJS加载的是一个对象(module.export),该对象只有在脚本运行完成之后才会生成,ES6不是对象,它对外的接口是一种静态定义,在代码静态解析阶段就会生成。
ES6的设计思想是尽量的静态化,这样做的好处是在编译的时候就能确定模块的依赖关系。以及输入输出的变量。而CommomJS和AMD模块都只能在运行的时候确定这些东西(运行时加载),由于只能在运行时加载,所以我们没有办法在编译的时候做静态优化。
严格模式
ES6模块是自动采用严格模式的,不管模块头部有没有’use strict‘
在ES6模块中,顶层的this指向undefined,所以不应该在顶层使用this
export
export用于导出模块内容,每一个模块都是一个独立的文件,该文件内部的所有变量在外部都是无法获取的。如果要获取一个模块内部的数据我们就需要使用export
// exportTest.js
<!--方法1-->
export let name = 'fanfan'
export let age = '18'
export function getData(){
console.log('export')
}
<!--方法2 优先考虑-->
let name = 'fanfan',age = '18';
function getData(){
console.log('export')
}
let alias = {name:"别名"}
export { name, age, getData, alias as aliasTest };
// 导出还可以使用as别名,当我们有冲突的字段的时候就可以使用到
export规定的是模块对外的接口,所以不能直接将里面的实际参数导出,例如下面的这种
export 1 // 这种是会直接报错的
由于export语句输出的接口,与其对应值是动态绑定关系,我们可以通过接口获取到模块内部实时的值
在CommonJS中的值是缓存的,没有这种现象
export let name = 'fanfan'
setTimeOut(()=> name = 'yeye',1000)
// 我们在其他模块中引用之后,一秒钟会获取到name的改变值是'yeye'
注意:export需要位于模块的最外层。不能将其放置在块级作用域中,否则就会报错!!
import
用于加载export导出的模块,from后面是导入的路径,支持相对路径和绝对路径
对应上面的导出:
// importTest.js
import { name, age, getData, aliasTest } from './exportTest'
// 导入的时候导入括号中的变量必须与导出的接口变量一一对应。如果想重新取一个名字,同样可以使用as别名实现
import { name as lastName } from './exportTest'
import 加载的变量都是只读的,因为他的本质是输入接口。所以是不允许修改被导入文件的。如果重新复制就会报错。
import 具有提升功能,也就是说不论你写在什么位置,都会提升到模块的最顶部,和export一样,import不能写在作用域中,这一点也是和CommonJS不同的地方。
import 会执行所加载的模块,所以我们可以使用下面的方法直接导入一些组件库来使用
import 'lodash'
如果使用import多次导入,只会执行一次。所以import语句是Singleton(单例)模式
模块的整体加载
// 当我们使用导入的都是一个模块中的数据的时候可以使用整体加载的方法
import * as user from './exportTest'
console.log(user.name) //fanfan
export default
默认导出
// exportDefault.js
export default {
.....
}
function getData(){}
export default getData
// importTest.js
import user from './exportDefault'
console.log(user.name) // fanfan
// 这里导入的名称命名可以是任意的。导入的时候也不需要大括号。
// 默认输入和普通导入可以同时使用
import _, { unset, clone } from 'lodash'
export 与 import 复合写法
当我们在一个模块中先导入一个然后导出相同的模块,可以使用复合写法。
但是这种方法是需要注意的是:在当前模块中并不能使用name和age,这个只是相当于一个转发的功能。
export { name, age } from './exportTest'
模块之间也可以进行继承
export * from './exportTest' // 转发出去exportTest中的数据,export * 会忽略下面的export default...
export { name as lastName } from './exportTest' // 改名之后转发出去exportTest中的数据
export default function(x){}
本片文章参考的是阮一峰老师的《ECMAScript 6 入门》,里面讲述的更加详细,有兴趣的同学可以去看看!