【前端模块化】-关于ES Module规范

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'
    
  2. 注意事项二:在打开对应的html文件,如果html中有使用模块化的代码,则必须开启一个服务来打开

    如果直接在浏览器中运行代码,会报如下错误:
    请添加图片描述

exports关键字

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

导出的方式:

  1. 在语句声明的前面直接加上export关键字

    export const name='孙悟空'
    export age=18
    export function sayHello(){
        console.log('hello')
    }
    
  2. 将所有需要导出的标识符,放到export后面的{}中

    export const name='孙悟空'
    export age=18
    
    export {
    	name,age
    }
    

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

  3. 导出时给标识符起一个别名——通过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'
    

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

  2. 导入时给标识符起别名——通过as关键字起别名

    import {name as fname,age} from './index.js'
    console.log(fname)
    
  3. 通过*将模块功能放到一个模块功能对象(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 Module规范_第1张图片

  1. 构建(Construction)根据地址查找js文件,并且下载将其解析成模块记录(ModuleRecord);
    【前端模块化】-关于ES Module规范_第2张图片

  2. 实例化(Instantiation),对模块记录进行实例化生成模块环境记录,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址。

  3. 运行(Evaluation)运行代码,计算值,并且将值填充到内存地址中
    【前端模块化】-关于ES Module规范_第3张图片

你可能感兴趣的:(前端,javascript,es6)