ES6:Module

430 阅读3分钟

ES6引入了一种新的模块加载方案,使用import来静态加载模块,而在此之前JS主要用的CommonJS和AMD进行模块的加载,属于动态加载,如require('fs')

意义: ES6模块是编译时加载,使静态分析成为可能,有了它能进一步拓宽JS语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能

  • 不再需要UMD模块格式了,将来服务器和浏览器都会支持 ES6 模块格式。目前,通过各种工具库,其实已经做到了这一点。
  • 将来浏览器的新 API 就能用模块格式提供,不再必须做成全局变量或者navigator对象的属性。
  • 不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供

而ES6模块的使用主要由export和import两个命令实现

export

export命令可以理解为对外输出,你可以把当前的js文件当作一个模块,然后用export对外输出一些模块内的变量,可以输出对象也可以输出函数,看看具体的用法

var year = 11
var weight = 70

function f1(x,y){
  return x*y
}

export var name = "John Reese"
export function add(x,y){
  return x + y
}
export {year,weight}
export {f1 as multiply}

//var m = 1
//export m 报错

export输出的值会进行动态更新,如:

export var i = 1;
setTimeout(()=> i = 2,500)

通过上面的模块import的i,会在500毫秒后变成2,而如果使用CommonJS则仅输出值的缓存,不存在动态更新

export命令应该出现在代码顶层,如果处在块级作用域内就会报错

function fn(){export var a = 1}//报错

import

import命令用于导入使用export命令导出的接口,使用方法如下

import {year,multiply,add} from './module1.js'
import {name as lastname} from './module1.js'

于是我们就可以直接使用导入的这些变量

  • 由import输入的变量都是只读的,但如果导入的是一个对象,那么我们可以修改其属性的值
  • import命令具有提升效果,会提升到整个代码顶部
  • 由于import是静态执行,所以我们不能在里面使用变量和表达式,也不能将其放入运行时才能知道结果的块中

再来看一些使用的例子

import './module1.js'//只执行不导入

import * as obj from './module1.js'//整体导入,加载到obj对象中

export default

export default用于指定默认输出

export default function(){console.log(1)}//默认输出

//....
import fn from './module1.js'//可以随意指定名字

export default实质上是对外输出了一个名叫default的变量,所以它的后面不能跟变量声明语句。再看看几种用法

var a = 1;
export {a as default};//等同于export default a

export default var b = 1;//报错

//....
import {default as fn} from './module1.js'
//等同于 import fn from ....

export与import复合

export {fn,fn2} from './module1'

//等同于
import {fn,fn2} from './module1'
export {fn,fn2}

export {fn as add} from './module1'//改名暴露
export * from './module1'//整体暴露
export {default} from './module1'//暴露默认接口

import()

import命令无法取代require()的动态加载功能,ES2020引入了import(),支持动态加载模块,它加载模块后返回的是一个Promise对象。

import('./module1')
.then(module => {
        console.log(module)//这里的module就是加载的整个模块
})

import('./module1')
.then({default,add} => {
        console.log(default,add)//可以使用结构赋值语法仅获取需要的接口
})