ES 模块用于在浏览器环境和服务器环境中使用。
模块就是以 .js
为扩展名的 JavaScript 文件。
普通脚本文件内的顶级的成员对其它脚本文件来说是公开(public)的全局上下文,而模块文件内的顶级的模块成员对其它模块文件来说都是私有(private)的,所以首先需要在模块中将它们显式导出,然后在其它模块中显式导入它们才可以使用。
注意:as 别名
只可以在 * as 别名
或 花括号 {}
内使用。
1.导出(export)
同一个模块中可同时存在命名导出和默认导出,但是为了减少命名导出和默认导出之间潜在的混淆,一些团队选择在整个项目中只坚持使用命名导出和默认导出中的其中一种,或者在整个项目中使用命名导出和默认导出两种但避免在同一个模块中混合使用它们。
注意:export
语句必须位于模块文件内的顶级。
1.1命名导出(named export)一个对象字面量
命名导出的值为一个对象字面量,对象字面量的属性则为需要导出的模块成员。
注意:实际上,导出的值不是一个对象字面量,在这里为了易于理解,暂且理解为一个对象字面量。
//前缀方式
//命名类
export class 类名 {
//类体
}
//匿名类
export {let | const} 类名 = class {
//类体
};
//变量
export let 变量名;
export let 变量名 = 值;
//常量
export const 常量名 = 值;
//命名函数
export function 函数名(形参) {
//函数体
}
//匿名函数
export {let | const} 函数名 = function (形参) {
//函数体
};
//箭头函数
export {let | const} 函数名 = (形参) => {
//函数体
};
//注意:不支持此语法。
export 字面量;
//末尾方式
//命名类
class 类名 {
//类体
}
//匿名类
{let | const} 类名 = class {
//类体
};
//变量
let 变量名;
let 变量名 = 值;
//常量
const 常量名 = 值;
//命名函数
function 函数名(形参) {
//函数体
}
//匿名函数
{let | const} 函数名 = function (形参) {
//函数体
};
//箭头函数
{let | const} 函数名 = (形参) => {
//函数体
};
//导出
export { 类名, 变量名, 常量名, 函数名 };
export { 类名 as 类别名, 变量名 as 变量别名, 常量名 as 常量别名, 函数名 as 函数别名 };
//注意:不支持此语法。
export { 字面量 };
export { 字面量 as 别名 };
1.2默认导出(default export)一个模块成员
默认导出的值为一个模块成员。
注意:因为 default
是别名,所以一个模块中只能有一个 export default
,不然会发生别名冲突。
//前缀方式
//命名类
export default class 类名 {
//类体
}
//匿名类
export default class {
//类体
}
//注意:不支持此语法。
export default let 变量名;
export default let 变量名 = 值;
export default const 常量名 = 值;
//命名函数
export default function 函数名(形参) {
//函数体
}
//匿名函数
export default function (形参) {
//函数体
}
//箭头函数
export default (形参) => {
//函数体
}
//字面量
export default 字面量;
//末尾方式
//命名类
class 类名 {
//类体
}
//匿名类
{let | const} 类名 = class {
//类体
};
//变量
let 变量名;
let 变量名 = 值;
//常量
const 常量名 = 值;
//命名函数
function 函数名(形参) {
//函数体
}
//匿名函数
{let | const} 函数名 = function (形参) {
//函数体
};
//箭头函数
{let | const} 函数名 = (形参) => {
//函数体
};
//导出
export { 类名 as default };
//注意:不支持此语法。
export { (new 类名()) as default };
export { 变量名 as default };
export { 常量名 as default };
export { 函数名 as default };
//注意:不支持此语法。
export { 字面量 as default };
//简写
export default 类名;
export default new 类名();
export default 变量名;
export default 常量名;
export default 函数名;
2.静态导入(import语句)
ES 模块的导入是异步并行加载的。
import
语句只可以在 ES 模块文件(支持导入 ES 模块 和 CommonJS 模块)内使用,不可以在 CommonJS 模块文件内使用。
注意:CommonJS 模块的模块成员是通过 ES 模块的默认导入方式导入的。
import ... from '模块标识符';
import '模块标识符';
'模块标识符'
必须为常量字符串字面量。
模块标识符
外围的引号支持 单引号('模块标识符'
) 或 双引号("模块标识符"
)。
模块标识符格式 | 描述 |
绝对路径:from '/module.js' 。相对路径: from './module.js' 、from '../module.js' 。URL: from 'https://example.com/module.js' 。 | 如果在浏览器中原生加载模块,则 模块标识符 末尾必须带有 .js 文件扩展名。如果是通过构建工具或第三方模块加载器打包或解析的 ES 模块,则 模块标识符 末尾可能非必须带有 .js 文件扩展名。 |
Node.js内置模块:from 'node:module' | ———————— |
包(实际上为目录名)内模块:from '包名' | ———————— |
注意:import
语句必须位于模块文件内的顶级。
注意:import
语句非必须位于模块文件内的顶部 ,但推荐将 import
语句放置在模块文件内的顶部。
注意:另一个模块无论在同一个模块中被加载(导入)多少次,实际上只会被加载(导入)一次。
2.1命名导入(named import)一个对象字面量
注意:实际上,使用的不是解构赋值语法,在这里为了易于理解,暂且理解为解构赋值语法。
//命名导出对应的导入方式
//方式一(直接将对象字面量赋值给别名)
//注意:如果模块标识符同时存在命名导出和默认导出,则*会同时导入命名导出和默认导出的模块成员。
//注意:不支持此语法。
import * from '模块标识符';
import * as 别名 from '模块标识符';
//方式二(使用解构赋值只导入打算使用的模块成员)
import { 类名, 变量名, 常量名, 函数名 } from '模块标识符';
import { 类名 as 类别名, 变量名 as 变量别名, 常量名 as 常量别名, 函数名 as 函数别名 } from '模块标识符';
2.2默认导入(default import)一个模块成员
//默认导出对应的导入方式
//方式一(使用解构赋值导入模块成员)
import { default as 别名 } from '模块标识符';
//方式二(直接将模块成员赋值给import后的标识符,标识符非必须与默认导出的模块成员名相同)
import 类名 from '模块标识符';
import 变量名 from '模块标识符';
import 常量名 from '模块标识符';
import 函数名 from '模块标识符';
2.3导入模块运行的结果
import '模块标识符';
无论 '模块标识符'
有没有模块成员的导出,并不导入任何模块成员,而是将模块运行的结果作为另一个模块的一部分,而不是将模块内的代码作为另一个模块的一部分。
3.再导出(re-export)
导入的模块成员可以在模块内不被使用而直接再导出。
再导出相当于先 import ... from '模块标识符'
语句 后 export
语句合二为一的语法糖。
注意:作为再导出的模块成员不可以在此模块中被使用。
注意:如果再导出的模块成员名称出现相同导致冲突,则模块内原本的模块成员的优先级高于导入的模块成员。
//命名导入再命名导出
//注意:如果模块标识符同时存在命名导出和默认导出,则*只会导入命名导出的模块成员,而不会导入默认导出的模块成员。
export * from '模块标识符';
export * as 别名 from '模块标识符';
export { 模块成员名 } from '模块标识符';
export { 模块成员名 as 模块成员别名 } from '模块标识符';
//命名导入再默认导出
export { 模块成员名 as default } from '模块标识符';
//默认导入再命名导出
export { default as 别名 } from '模块标识符';
//默认导入再默认导出
export { default } from '模块标识符';
4.动态导入(import()运算符)
import
运算符既可以在 ES 模块文件(支持导入 ES 模块 和 CommonJS 模块)内使用,还可以在 CommonJS 模块文件(支持导入 ES 模块 和 CommonJS 模块)内使用。
注意:CommonJS 模块的模块成员是通过 ES 模块的默认导入方式导入的。
import('模块标识符');
import()
看起来像是函数调用,其实只是碰巧使用了圆括号 ()
,实际上是运算符。'模块标识符'
外围的圆括号 ()
不可以省略,否则会被认为是 import
语句。
'模块标识符'
非必须为常量字符串字面量,可以是任何求值为字符串的表达式。
模块标识符
外围的引号支持 单引号('模块标识符'
) 或 双引号("模块标识符"
)。
模块标识符格式参考静态导入章节。
import()
运算符的返回值为 Promise
对象,此 Promise
对象会被解决为一个包含所有导出(命名导出和默认导出)的对象字面量。
注意:import()
运算符非必须位于模块文件内的顶级,可以嵌套到其它语句内。
注意:import()
运算符非必须位于模块文件内的顶部。
注意:另一个模块无论在同一个模块中被加载(导入)多少次,实际上只会被加载(导入)一次。
注意:当动态导入用于在浏览器环境中时,<script>
标签不需要 type="module"
属性。
//say.js
export function hello() {
console.log("Hello");
}
export function bye() {
console.log("Bye");
}
//index.js
let { hello, bye } = await import('./say.js');
hello();
bye();
//输出
Hello
Bye
5.import.meta对象
import.meta
对象包含当前模块的元信息。
浏览器环境:
如果是 <script type="module">
的外部方式,则 import.meta.url
的值为模块文件的 URL。
如果是 <script type="module">
的内部方式,则 import.meta.url
的值为模块所在 HTML 的 URL。
服务器环境:
如果是 Node.js,则 import.meta.url
的值为 file://...
。
6.await关键字
await
关键字不仅仅可以被使用在 async
函数体内,还可以被使用在模块文件内的顶级。
//命名导出
//前缀方式
export const five = await Promise.resolve(5);
//末尾方式
const five = await Promise.resolve(5);
export { five };
//默认导出
//前缀方式
export default await Promise.resolve(5);
//末尾方式
//方式一
const five = await Promise.resolve(5);
export default five;
//方式二
const five = Promise.resolve(5);
export default await five;
原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/javascript/javascriptlang/3556.html