ES Module规范

认识ES Module

ES Module和CommonJS的模块化有一些不同之处:

  • 一方面它使用了importexport关键字;
  • 另一方面它采用编译期的静态分析,并且也加入了动态引用的方式;

ES Module模块采用export和import关键字来实现模块化:

  • export负责将模块内的内容导出;
  • import负责从其他模块导入内容;

采用ES Module将自动采用严格模式:use strict

  1. 注意事项一:在浏览器中使用ES Module时,必须在文件后加上后缀名 .js
const name='abc'
const age=12
function sayHello(){
    console.log('hello')
}
//导出
exports {
    name,age,sayHello
}

引入时的路径必须包含后缀名!

import {name,age,sayHello}  from './index.js'
  1. 注意事项二:在打开对应的html文件,如果html中有使用模块化的代码,则必须开启一个服务来打开
    如果直接在浏览器中运行代码,会报如下错误:

exports关键字

export关键字将一个模块中的变量、函数、类等导出

导出的方式:

  1. 在语句声明的前面直接加上export关键字
export const name='孙悟空'
export age=18
export function sayHello(){
    console.log('hello')
}
  1. 将所有需要导出的标识符,放到export后面的{}中
export const name='孙悟空'
export age=18

export {
	name,age
}

注意:这里的**{}里面不是ES6的对象字面量的增强写法**,{}也不是表示一个对象的;

  1. 导出时给标识符起一个别名——通过as关键字起别名
export const name='孙悟空'
export const age=18

export {
	name as fname,
   	age as fage
}

导入时应导入别名:

import {fname,fage} from './index.js'

import关键字

import关键字负责从另外一个模块中导入内容

导入方式:

  1. import {标识符列表} from ‘模块’;
import {name,age}  from './index.js'

这里的{}也不是一个对象,里面只是存放导入的标识符列表内容

  1. 导入时给标识符起别名——通过as关键字起别名
import {name as fname,age} from './index.js'
console.log(fname)
  1. 通过*将模块功能放到一个模块功能对象(a module object)上,将整个模块导入进来
const name='孙悟空'
const age=18

export {
	name,age
}

导入时:

import * as index from './index.js'
console.log(index.name,index.age)

export和import结合使用

//从index.js文件(模块)中引入name、age并导出
export {name,age} from './index.js'

//从index.js文件(模块)中引入所有并导出
export * from './index.js'

default用法

前面我们学习的导出功能都是有名字的导出(named exports)

  • 在导出export时指定了名字;
  • 在导入import时需要知道具体的名字;

还有一种导出叫做默认导出(default export)

  • 默认导出export时可以不需要指定名字
  • 导入时不需要使用{},并且可以自己来指定名字
  • 它也方便我们和现有的CommonJS等规范相互操作;

注意:在一个模块中,只能有一个默认导出(default export)

function parseLyric(){
    return '歌词'
}
//默认导出
export default parseLyric

也可以直接定义标识符直接作为默认导出

export default function(){
	return '歌词'
}

如果导出方式是默认导出,则导入时不需要使用大括号,并且可以随便起一个变量名接收

import  aaa  from './parse.js'

import函数

通过import加载一个模块(import声明语法),是不可以在其放到逻辑代码中的,比如:

let flag=true
if(flag){
    //不允许在逻辑代码中编写import导入声明语法,只能写到js代码顶层
    import {name,age} from './index.js'//会报错!
}

原因:

  • 这是因为ES Module在被JS引擎解析时,就必须知道它的依赖关系;
  • 由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况;

但是某些情况下,我们确确实实希望动态的来加载某一个模块,比如:根据不同的条件,动态来选择加载模块的路径

这个时候我们需要使用import()函数来动态加载

let flag=true
if(flag){
    import('./index.js').then(res=>{
        console.log(res.name,res.age)
    })
}else{
    import('./bbb.js').then(res=>{
        res.sayHelo()
    })
}

import meta

import.meta是一个给JavaScript模块暴露特定上下文的元数据属性的对象:

  • 它包含了这个模块的信息,比如说这个模块的URL;
  • 在ES11(ES2020)中新增的特性;

ES Module的解析过程

ESModule的解析过程可以划分为三个阶段:

es规范是什么_javascript

  1. 构建(Construction)根据地址查找js文件,并且下载将其解析成模块记录(ModuleRecord);
  2. 实例化(Instantiation),对模块记录进行实例化生成模块环境记录,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址。
  3. 运行(Evaluation)运行代码,计算值,并且将值填充到内存地址中