JavaScript模块化编程:构建高效、可维护的代码结构

引言

JavaScript 模块是现代前端开发中的重要组成部分。它们允许开发者将代码组织成独立、可重用的单元,从而提高了代码的可维护性、可扩展性和可读性。本文将深入探讨 JavaScript 模块的概念、语法和最佳实践,帮助你充分利用模块化开发的优势。

模块的基本概念

JavaScript 模块是指将代码封装在单独的文件中,并按需导出和导入其中的功能。它们可以包含变量、函数、类和其他任何 JavaScript 实体。模块有自己的作用域,而不是和脚本一样在全局作用域内执行代码。一组相互导入、导出的模块组成的图形通常被称为模块树。

模块的语法

在过去,JavaScript 没有原生的模块系统,但随着 ECMAScript 6(ES6)的出现,现在我们可以使用 importexport 关键字来定义和使用模块。

  • 导出介绍

一个模块可包含多个 命名导出 以及 单个默认导出。可使用导出声明指定从模块中导出的内容,声明以关键字 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';

注意:

  • 只用模块中的代码才可使用声明式的 exportimport ,非模块代码不能使用。

  • importexport的声明只能出现在模块顶层作用域,而不能出现在任何控制流程的结构中。例如循环和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();

模块的好处

  1. 组织性: 模块化使得代码结构更加清晰,易于维护和扩展。每个模块都专注于特定功能,降低了代码的复杂度。

  2. 封装性: 模块允许将功能封装在单独的文件中,并通过导出和导入控制模块的可访问性,从而提高了代码的安全性和可靠性。

  3. 重用性: 模块化使得代码可以被轻松地重用。一个模块定义的功能可以在多个地方导入和使用,避免了重复编写相似的代码。

  4. 依赖管理: 使用模块可以更好地管理代码之间的依赖关系。每个模块只需关注自己的依赖,而不必担心全局作用域的污染。

最佳实践

  1. 单一职责原则: 每个模块应该只负责一项功能或功能集合,保持代码的简洁和可维护性。

  2. 明确导入和导出: 在模块的顶部明确导出模块提供的功能,并在导入时明确指定需要的功能,避免导入整个模块。

  3. 模块命名规范: 使用有意义的文件名和模块名,遵循命名约定,使代码更易读、易懂。

  4. 避免循环依赖: 尽量避免模块之间的循环依赖,这会导致代码不稳定和难以维护。

结语

JavaScript 模块为开发者提供了一种强大的工具,用于组织、封装和重用代码。通过合理地利用模块化开发的技术和最佳实践,我们可以构建出更加灵活、可靠和可维护的应用程序。开始使用模块化开发,解锁 JavaScript 开发的新境界!

喜欢的话帮忙点个赞 + 关注吧,将持续更新 JavaScript 相关的文章,还可以关注我的公众号 梁三石FE ,感谢您的关注~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/4566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Three.js和Cesium.js中坐标

在了解Three.js和Cesium.js前先了解并弄清楚图形学关于空间的基本概念流程: 计算机图形学 图形学中涉及到多个坐标空间,这些空间之间的变换是图形渲染中的核心部分。下面是一些常见的图形学空间及其变换顺序: 对象空间(Object Sp…

Python快速入门1数据类型(需要具有编程基础)

数据类型: Python 3.0版本中常见的数据类型有六种: 不可变数据类型可变数据类型Number(数字)List(列表)String(字符串)Dictionary(字典)Tuple(元…

【InternLM】基于弱智吧数据的微调数据构造实验

1. 数据处理流程 在AI领域有句名言:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。可见数据对整个AI的决定性影响,在模型开源化的今天,很多厂商的模型结构都大同小异,那影响最终模型的一大决定因…

学习redis知识点

学习 Redis 时,可以按照以下分类来组织知识点: 核心概念 内存数据库:理解 Redis 作为内存数据库的特点和限制。数据结构:熟悉 Redis 支持的数据结构,如字符串、列表、集合、有序集合和散列。 数据类型及操作 字符串…

4.28java项目小结

这几天完成了用户修改资料模块的功能,实现了修改用户头像,昵称等信息,并且对数据库进行了操作,大致画了好友资料的页面的内容,这两天尽量完成表的创建,建立多对多的关系,实现好友的添加功能。

.DevicData-P-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复

引言: 随着信息技术的飞速发展,网络安全问题日益凸显,其中勒索病毒以其独特的攻击方式和巨大的破坏性引起了广泛关注。.DevicData-P-XXXXXXXX勒索病毒就是近期出现的一种新型勒索病毒,它利用强大的加密算法和巧妙的传播手段&…

HNCTF 2022 week1 题解

自由才是生活主旋律。 [HNCTF 2022 Week1] Interesting_include <?php //WEB手要懂得搜索 //flag in ./flag.phpif(isset($_GET[filter])){$file $_GET[filter];if(!preg_match("/flag/i", $file)){die("error");}include($file); }else{highlight_…

求解素数环问题

注&#xff1a;这里我的代码是以第一位为最大数n为首元素不动的 思路&#xff1a; 首先我们分析问题要以较小规模的样例进行分析&#xff0c;例如n3时 第一步&#xff1a;深入搜索 我们先不管后面怎么样&#xff0c;当前的首要目标是先确定第一个元素的值&#xff0c;可知有…

windows电脑改造为linux

有个大学用的旧笔记本电脑没啥用了&#xff0c;决定把它改成linux搭一个服务器&#xff1b; 一、linux安装盘制作 首先要有一个大于8G的U盘&#xff0c;然后去下载需要的linux系统镜像&#xff0c;我下的是ubuntu&#xff0c;这里自选版本 https://cn.ubuntu.com/download/d…

今日arXiv最热NLP大模型论文:韩国团队提出ResearchAgent系统,模仿人类产出论文idea

你是否还在苦于想发论文却没有idea&#xff1f; 在浩瀚无边的文献中苦苦寻找却又无从下手&#xff1f; 那些看似与你研究相关的文章&#xff0c;要么已经被人研究得透彻无比&#xff0c;要么与你的方向南辕北辙&#xff0c;让你倍感挫败。 不要慌&#xff0c;让AI来助你一臂之…

日期类的实现,const成员

目录 一&#xff1a;日期类实现 二&#xff1a;const成员 三&#xff1a;取地址及const取地址操作符重载 一&#xff1a;日期类实现 //头文件#include <iostream> using namespace std;class Date {friend ostream& operator<<(ostream& out, const Dat…

C语言中的三大循环

C语言中为我们提供了三种循环语句&#xff0c;今天我就来与诸君细谈其中之奥妙。循环这一板块总结的内容较多&#xff0c;而且&#xff0c;很重要&#xff01;&#xff08;敲黑板&#xff01;&#xff01;&#xff01;)&#xff0c;所以诸君一定要对此上心&#xff0c;耐住性子…

系统服务(22年国赛)—— nmcli命令部署VXLAN

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; 系统服务&#xff08;22年国赛&#xff09;—— VXLAN服务部署https://myweb.myskillstree.cn/118.html 目录 题目&#xff1a; AppSrv 关闭防火墙和SEli…

Linux 双击sh脚本运行无反应或一闪而退【已解决】

这里写目录标题 一、问题描述二、解决思路1. 开启终端&#xff0c;使用命令行运行.sh脚本文件2. 终端中运行可以&#xff0c;但双击之后运行闪退 (遇到了个这个奇奇怪怪的问题) 三、分析记录3.1 .bashrc设置变量的作用域3.2 环境变量冲突覆盖问题. 四、相关知识点4.1 环境变量配…

CSS详解(一)

1、css工作中使用场景 美化网页&#xff08;文字样式、背景样式、边框样式、盒子模型、定位、动画、&#xff09;&#xff0c;布局页面&#xff08;flex布局、响应式布局、媒体查询&#xff09; 2、CSS 规则 通常由两个主要部分组成选择器和样式声明 2.1选择器 选择器指定了…

C语言-用二分法在一个有序数组中查找某个数字

1.题目描述 有15个数按由大到小顺序放在一个数组中&#xff0c;输入一个数&#xff0c;要求用折半查找法找出该数是数组中第几个元素的值。如果该数不在数组中&#xff0c;则输出“无此数” 二.思路分析 记录数组中左边第一个元素的下标为left&#xff0c;记录数组右边第一个…

Spring AI聊天功能开发

一、引入依赖 继承父版本的springboot依赖&#xff0c;最好是比较新的依赖。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.4</version><relativePat…

【JavaScript】转化为布尔值boolean的几种情况

1 转化为布尔值boolean时为false的6种情况 下面6种值转化为布尔值时为false&#xff0c;其他转化都为true&#xff1a; 1、undefined2、null&#xff08;代表空值&#xff09;3、0&#xff08;数字0布尔值为false&#xff0c;字符串"0"布尔值为true) (数字0转布尔类…

C++笔试强训day10

目录 1.最长回文字符串 2.买卖股票的最好时机(一) 3.过河卒 1.最长回文字符串 链接 一开始没认真看题目&#xff0c;直到提交了好几遍没过还是没去检查题目&#xff0c;一直检查代码逻辑&#xff0c;哎呦&#xff0c;难受了。 我以为是收尾字母相同就行了。 错误代码&…

为什么二维数组初始化第一维数组长度可以为空,第二维不可以为空呢?

注意&#xff0c;数组第二维的长度声明永远不能省略。这是因为C语言中的二维数组元素在c编译程序为其分配的连续存储空间中是按行存放的&#xff0c;即存在完整第一行后存第二行&#xff0c;然后再第三行&#xff0c;以此类推。存放时系统必须知道每一行有多少个元素才能正确计…