46.ESModule详解

认识 ES Module

JavaScript没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等,所以在ES推出自己的模块化系统时,大家也是兴奋异常。
ES Module和CommonJS的模块化有一些不同之处:

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

ES Module模块采用exportimport关键字来实现模块化:

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

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

ESModule的基本使用

image.png

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 给script标签添加属性type为module,告诉其加载的不是一个普通的js文件,而是一个js模块 -->
    <script src="./src/main.js" type="module"></script>
  </body>
</html>

./src/main.js

import { name, age } from "./foo.js";
console.log(name, age);

./src/foo.js

// export关键字后直接跟变量声明
export const name = "why";
export const age = 18;

image.png

export导出和import导入的方式

1.export导出的几种方式

  • 1.变量在声明时直接导出,即export后跟变量声明语句
  • 2.变量声明后,统一导出
  • 3.统一导出时给导出的变量起别名

1.变量在声明时直接导出,即export后跟变量声明语句
./src/foo.js

export const name = "why";
export const age = 18;

export function sum(a, b) {
  return a + b;
}

export class Person {
  constructor(name) {
    this.name = name;
  }
}

./src/main.js

import { name, age, sum, Person } from "./foo.js";
console.log(name, age);

sum(1, 2);

const person = new Person("lily");
console.log(person);

2.变量声明后,统一导出
./src/bar.js

const name = "why";
const age = 18;

function sum(a, b) {
  return a + b;
}

class Person {
  constructor(name) {
    this.name = name;
  }
}

//export关键字后面的{}不是一个对象,而是一种语法
export { name, age, sum, Person };

./src/main.js

import { name, age, sum, Person } from "./foo.js";
console.log(name, age);

sum(1, 2);

const person = new Person("lily");
console.log(person);

3.统一导出时给导出的变量起别名

const name = "why";
const age = 18;

function sum(a, b) {
  return a + b;
}

class Person {
  constructor(name) {
    this.name = name;
  }
}

//3.统一导出时使用as关键字给变量起别名
export { name as bName, age as bAge, sum as bSum, Person as BPerson };

./src/main.js
导入时要导入变量起的别名

import { bName, bAge, bSum, BPerson } from "./baz.js";
console.log(bName, bAge);

bSum(1, 2);

const person1 = new BPerson("lily");
console.log(person1);

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

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

方式一:

const height = 1.88;

export default height;

方式二:

const height = 1.88;

export {
  height as default
};

./src/main.js
导入模块的默认导出时,直接导入即可

import height from "./demo.js";
console.log(height)

2.import导入的几种方式:

方式一:

import { name, age, sum, Person } from "./foo.js";
console.log(name, age);

sum(1, 2);

const person = new Person("lily");
console.log(person);

import { bName, bAge, bSum, BPerson } from "./baz.js";
console.log(bName, bAge);

bSum(1, 2);

const person1 = new BPerson("lily");
console.log(person1);

方式二:导入变量时给变量起别名

import {
  name as barName,
  age as barAge,
  sum as barSum,
  Person as BarPerson,
} from "./bar.js";
console.log(barName, barAge);

barSum(1, 2);

const person3 = new BarPerson("lily");
console.log(person3);

方式三:整体导入并起别名

import * as baz from "./baz.js";
console.log(baz.name, baz.age);

baz.sum(1, 2);

const person2 = new baz.Person("lily");
console.log(person2);

方式四:导入模块默认导出的变量

import height from "./demo.js";
console.log(height);

3.导入导出结合使用

image.png

./util/format.js

function timeFormat(str) {
  return "2022-03-08";
}
function priceFormat(num) {
  return '99.00';
}

export { timeFormat, priceFormat };

./util/math.js

function sum(a, b) {
  return a + b;
}
function mul(a, b) {
  return a * b;
}

export { sum, mul };

./util/index.js

//导出方式一:
import { timeFormat, priceFormat } from "./format.js";
import { mul, sum } from "./math.js";

export { timeFormat, priceFormat, sum, mul };
//导出方式二:
export { timeFormat, priceFormat } from "./format.js";
export { sum, mul } from "./math.js";
//导出方式三:
export * from "./format.js";
export * from "./math.js";

./src/main.js

import { timeFormat, priceFormat, sum, mul } from "./utils/index.js";

console.log(timeFormat("2022/03/18"));
console.log(priceFormat(99));
console.log(sum(1, 2));
console.log(mul(1, 2));

import函数

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


image.png

为什么会出现这个情况呢?

  • 这是因为ES Module在被JS引擎解析时,就必须知道它的依赖关系;
  • 由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况;
  • 甚至下面的这种写法也是错误的:因为我们必须到运行时能确定path的值;

但是某些情况下,我们确确实实希望动态的来加载某一个模块:

  • 如何根据不同的条件,动态来选择加载模块的路径;
  • 这个时候我们需要使用 import() 函数来动态加载
    image.png

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

  • 它包含了这个模块的信息,比如说这个模块的URL;
  • 在ES11(ES2020)中新增的特性
// 获取当前文件的绝对路径
console.log('当前文件所在目录', import.meta.url)
image.png

在webpack环境下,ESModule和Commonjs是可以相互导入导出的

foo.js

//commonJs导出
const name = 'why'
const age = 18
module.exports = {name,age}

bar.js

//ESModule导出
function sum(a,b) {
  return a + b
}
export { sum }

index.js

import {name, age} from './foo.js'
const bar = require('./bar.js')
console.log(name,age)
bar.sum(1,2)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容