引言
JavaScript
模块是现代前端开发中的重要组成部分。它们允许开发者将代码组织成独立、可重用的单元,从而提高了代码的可维护性、可扩展性和可读性。本文将深入探讨 JavaScrip
t 模块的概念、语法和最佳实践,帮助你充分利用模块化开发的优势。
模块的基本概念
JavaScript
模块是指将代码封装在单独的文件中,并按需导出和导入其中的功能。它们可以包含变量、函数、类和其他任何 JavaScript
实体。模块有自己的作用域,而不是和脚本一样在全局作用域内执行代码。一组相互导入、导出的模块组成的图形通常被称为模块树。
模块的语法
在过去,JavaScript 没有原生的模块系统,但随着 ECMAScript 6(ES6)的出现,现在我们可以使用 import
和 export
关键字来定义和使用模块。
- 导出介绍
一个模块可包含多个 命名导出
以及 单个默认导出
。可使用导出声明指定从模块中导出的内容,声明以关键字 export
开头,示例如下:
export function fun() {// ...
}export const name = 'aa';
- 导入介绍
可以使用 导入声明
(也被称为静态导入) 或 动态导入
来加载模块并从其中导入内容。导入声明使用关键字 import
,接着是要导入的内容,然后是关键字 from
,之后是指定从哪一个模块导入的模块说明符的字符串字面量。示例如下:
import { fun } from './mod.js';
import { fun1 } from './mod.js';或import { greet, pi } from './myModule.js';
- 默认导出
一个模块只能有一个默认导出或者没有,多个默认导出,代码会报错。注意单词 default
。
export default functio test() {// ...
}或function test() {}export default test;
默认导出对应的导入方式如下,注意这里没有大括号。
import test from './mod.js';
- 只是简单导入
也可以不列出任何导入的内容,从而只使用导入模块的副作用。只是加载对应的模块以及它依赖的模块,并且执行它的代码,但是不导入任何内容。
import './modk.js';
注意:
-
只用模块中的代码才可使用声明式的
export
和import
,非模块代码不能使用。 -
import
和export
的声明只能出现在模块顶层作用域,而不能出现在任何控制流程的结构中。例如循环和if语句。 -
模块只能导出它声明的内容或重新导出它导入的内容。
模块导出方式
- 直接把关键字
export
放在声明或定义的前面
export const age = 32;
export let name = 'javascript';
export var username = 'jack';
export function test() {}
export class Example {}
- 导出的位置不必和创建的位置相同,可以独立使用导出单个声明,也可独立使用多个声明。
const age = 32;
let name = 'javascript';
var username = 'jack';
function test() {}
class Example {}// 独立使用单个声明
export { age, name, username, test, Example };// 独立使用多个声明export { age, name };
export { username };
export { test, Example };
- 导出声明可在代码结尾、开头或中间的任何位置:下面展示将单个声明放在代码开头位置
export { age, name, username, test, Example };const age = 32;
let name = 'javascript';
var username = 'jack';
function test() {}
class Example {}
- 模块中不同导出风格可以混用
export const age = 32;
let name = 'javascript';
var username = 'jack';export function test() {}
class Example {}
export { name, username, Example };
注意导出的唯一限制是 导出的名称必须是唯一的
,不能重复。
模块说明符
以示例解释:
import { test } from './ab.js';
模块说明符指的是单词 from
后面的 './ab.js'
部分。在导入声明中,模块说明符必须是一个 字符串字面量
,不能只是返回字符串的表达式,因为声明是静态的,在执行代码前必须解析他们。单引号或双引号都可以使用。
浏览器中使用
模块说明符要么是 绝对URL
,要么是以 /(斜线)
, ./(点斜线)
, ../(点点斜线)
开头的 相对URL
。模块有最终解析的 URL
确定。
以下有效说明符介绍:
import /*...*/ from "http://test.com/a.js"; // 绝对路径
import /*...*/ from "/a.js"; // 以 / 开始
import /*...*/ from "./bbb.js"; // 以 ./ 开始
import /*...*/ from "../ccc.js"; // 以 ../ 开始
import /*...*/ from "./test/a.js"; // 以 ./ 开始
以下在目前浏览器中, 是无效的:
import /*...*/ from "a";
import /*...*/ from "a.js";
重命名导出
从模块导出的标识符不必与模块代码中的标识符相同,可以使用导出声明中的 as
子句重命名导出:
let name = 'java';
export { name as username };
在另一个模块使用名称 username
将其导入:
import { username } from './a.js';
name
只是仅用户模块内部,而不是模块外部。只能在独立导出时使用重命名,而不能在内联导出时使用重命名。
export let name as username = 'java'; // 这样重命名是错误的
如果想创建别名,可以使用一个内联命名导出,然后使用重命名导出:
export let name = "java";export { name as usernam };// 这样为同一个函数创建了两个导出: name 和 username
重新导出另一个模块的导出
模块可以重新导出另一个模块的导出:
export { name } from './b.js';
使用 星号(*)
来导出其他模块的所有 命名导出
,不能导出 默认导出
。
export * from "./a.js";
重新导出时可以使用 as
字句更改导出的名称:
export { name as username } from './ab.js';
重命名导入
如果两个模块都导出了函数test, 并且想在模块中使用这两个函数,或者模块使用的名称与代码某些内容冲突,这时可以使用 as
子句进行重命名导入。
import { test as testOne } from './a.js';
import { test as testTwo } from './b.js';// 调用它们
testOne();
testTwo();
模块的好处
-
组织性: 模块化使得代码结构更加清晰,易于维护和扩展。每个模块都专注于特定功能,降低了代码的复杂度。
-
封装性: 模块允许将功能封装在单独的文件中,并通过导出和导入控制模块的可访问性,从而提高了代码的安全性和可靠性。
-
重用性: 模块化使得代码可以被轻松地重用。一个模块定义的功能可以在多个地方导入和使用,避免了重复编写相似的代码。
-
依赖管理: 使用模块可以更好地管理代码之间的依赖关系。每个模块只需关注自己的依赖,而不必担心全局作用域的污染。
最佳实践
-
单一职责原则: 每个模块应该只负责一项功能或功能集合,保持代码的简洁和可维护性。
-
明确导入和导出: 在模块的顶部明确导出模块提供的功能,并在导入时明确指定需要的功能,避免导入整个模块。
-
模块命名规范: 使用有意义的文件名和模块名,遵循命名约定,使代码更易读、易懂。
-
避免循环依赖: 尽量避免模块之间的循环依赖,这会导致代码不稳定和难以维护。
结语
JavaScript
模块为开发者提供了一种强大的工具,用于组织、封装和重用代码。通过合理地利用模块化开发的技术和最佳实践,我们可以构建出更加灵活、可靠和可维护的应用程序。开始使用模块化开发,解锁 JavaScript
开发的新境界!
喜欢的话帮忙点个赞 + 关注吧,将持续更新 JavaScript
相关的文章,还可以关注我的公众号 梁三石FE
,感谢您的关注~