ES Module -JavaScript的模块化

343 阅读3分钟

一.静态加载

1.ES Module运行环境

在node中运行

1.将文件扩展名改为.mjs

//other.mjs
export const name = "Cristiano"
export const sport = "football"

//index.mjs
import { name, sport } from "./other.mjs"
console.log(name, sport);  //Cristiano football

2.在package.json中配置type为"module"

//package.json
{
  "type": "module"
}
//other.js
export const name = "Cristiano"
export const sport = "football"

//index.js
import { name, sport } from "./other.js"
console.log(name, sport);  //Cristiano football

在浏览器中运行

在html的script标签中加上type="module"

<script src="./index.js" type="module"></script>

不能通过本地加载html文件,可以通过VSCode下载插件Live Server打开

image.png

2.export

一个模块就是一个独立的文件,export可以导出变量、函数、类,有几种不同的导出方式:

方式一: 导出声明语句

   //other.js
export const name = "Cristiano"
export function getGoldenGlobeAward() {
   console.log("CR7");
}
export class Sports { 
  constructor() {
    this.name = "football"
  }
}

方式二: 将标识符一起导出

 //other.js
const name = "Cristiano"
function getGoldenGlobeAward() {
   console.log("CR7");
}
class Sports { 
  constructor() {
    this.name = "football"
  }
}
export { name, getGoldenGlobeAward, Sports }

方式三: 使用(as)关键字重命名

 //other.js
export const name = "Cristiano"
export function getGoldenGlobeAward() {
  return "CR7"
}
export class Sports {
  constructor() {
    this.name = "football"
  }
}
export { name as crName, getGoldenGlobeAward as getFootballer, Sports as BallGame }

注意: export关键字不能出现在函数或者块级作用域中,否则无法静态加载

 //other.js
let flag = true
if (flag) {
  export const name = "CR7"  //SyntaxError: Unexpected token 'export'
}
//other.js
function foo() {
  export const name = "CR7" //SyntaxError: Unexpected token 'export'
}
foo()

3.import

方式一:大括号里面的变量名,必须与被导入模块(other.js)对外接口的名称相同

//index.js
import { name, getGoldenGlobeAward, Sports } from "./other.js"

方式二: 使用(as)关键字重命名

//index.js
import { name as crName, getGoldenGlobeAward as getFootballer, Sports as BallGame } from "./other.js"

方式三: 使用(*)整体导入

//index.js
import * as wholeIdentifier from "./other.js"
console.log(wholeIdentifier.name)  //Cristiano
console.log(wholeIdentifier.getGoldenGlobeAward()) //CR7

import代码在编译阶段执行的,在代码运行之前,所以有提升作用

console.log(wholeIdentifier.getGoldenGlobeAward());
import * as wholeIdentifier from "./other.js"  //CR7

4.export和import结合用法

先输入后输出同一个模块,这样可以将所有接口放到一个文件中,方便阅读和管理

//other.js
 export { add, sub } from './math.js'
 //接口改名
 export { timeFormat as dateFormat, priceFormat as moneyFormat } from './format.js'
//other.js
//整体导出
export * from './math.js'
//整体改名导出
export * as whatever from './format.js'

注意:other.js模块中并没有导入add, sub,只是对外转发,所以当前模块不能使用这些接口

//统一管理
import { add, sub, dateFormat, moneyFormat} from 'other.js'

5.export default(一个模块中只能有一个)

import命令后面不使用大括号,export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令

export default后面不需要具体函数或变量名,export default本质上就是输出一个叫做default的变量或方法,导入时可以取任意名字

//other.js
export default function () {
  console.log("CR7");
}
//index.js
import getName from "./other.js" //不使用{}大括号,getName可以随便取名
console.log(getName());  //CR7
//other.js
export default "CR7" //此时接口就是default

二.动态加载(import()函数

importexport命令只能在模块的顶层,不能在代码块之中(比如,在if代码块之中,或在函数之中) import()函数支持动态加载模块,返回一个Promise对象,可用于以下几种情形:

1.按需加载模块

//other.js
const name = 'CR7'
const age = 37
const country = "Portugal"
export{name,age,country}

//index.js
function beWiminner() {
  import("./other.js").then(({name,age,country}) => {
    console.log(name);
    console.log(age);
    console.log(country);
  })
}
beWiminner()
//beWinner函数执行才会加载模块,可以通过解构拿到输出接口

2.条件加载

if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}
//根据不同条件加载模块

3.获取动态路径

import(foo())
.then(...);
//根据函数foo返回的路径加载模块