【12】ES6:模块化

一、JavaScript 模块化

JavaScript 模块化是一种组织和管理 JavaScript 代码的方法,它将代码分割为独立的模块,每个模块都有自己的作用域,并且可以导出和导入功能。模块化可以提高代码的可维护性、可重用性和可扩展性。

在JavaScript中,有几种常见的模块化规范和工具,包括:

CommonJS:

CommonJS 是一种服务器端 JavaScript 模块化规范,主要用于 Node.js。使用 require() 函数导入模块,使用 module.exports 或 exports 导出模块。支持同步加载模块,因此在浏览器端可能会阻塞页面渲染。适用于服务器端开发,模块的加载是在运行时发生的。
// CommonJS模块
let { stat, exists, readfile } = require('fs')// 等同于
let _fs = require('fs')
let stat = _fs.stat
let exists = _fs.exists
let readfile = _fs.readfile

上面代码的实质是整体加载 fs 模块(即加载 fs 的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。

AMD (Asynchronous Module Definition):

AMD 是一种浏览器端 JavaScript 模块化规范,旨在解决异步加载模块的问题。使用 define() 函数定义模块,并使用 require() 函数异步导入模块。支持异步加载模块,在运行时按需加载模块,不会阻塞页面渲染。适用于浏览器端开发,特别是在网络环境较慢的情况下。

UMD (Universal Module Definition):

UMD 是一种通用的 JavaScript 模块化规范,旨在兼容 CommonJS 和 AMD 规范。根据环境判断是否支持 CommonJS、AMD 或全局对象,并采取相应的模块化方式。可以在服务器端和浏览器端都使用,兼容不同的模块化规范。

ES6 (ES2015) 模块化:

ES6 模块化是 ECMAScript 2015 引入的官方标准模块化规范。使用 import 和 export 关键字来导入和导出模块。静态分析:可以在编译时进行静态分析,提前处理模块依赖关系。支持默认导出和命名导出,支持动态导入。在现代浏览器和Node.js中得到广泛支持。
// ES6模块
import { stat, exists, readFile } from 'fs'

上面代码的实质是从 fs 模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。

ES6 模块化是目前被广泛使用的标准模块化规范,它提供了更加简洁、灵活的语法,并且在编译阶段进行静态分析,能够提高性能。大多数现代的 JavaScript 开发都采用 ES6 模块化来组织和管理代码,尤其是在使用构建工具(如Webpack、Rollup等)进行项目构建时。

二、ES6 Module

模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。

1、导出(export)

(1)命名导出(Named Exports): 使用 export 命令指定导出一个变量(var、let、const)、函数(functions)或类(class)。

导出变量

// 导出变量
export const name = 'Amy'
export let age = 20
export const city = 'Beijing'// 等同于(推荐)
const name = 'Amy'
let age = 20
const city = 'Beijing'
export { name, age, city }
// 使用 as 关键字重命名
export { name as firstName }// ----------------------------------------
// export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
// 以下写法报错
export 1 // 直接输出
export name // 通过变量 m,还是直接输出 1

导出函数

export function multiply(x, y) {return x * y
}export function calculateSum(a, b) {return a + b
}// 等同于
function multiply(x, y) {return x * y
}
function calculateSum(a, b) {return a + b
}
export { multiply, calculateSum }// 报错
export multiply

导出类

export class Person {constructor(name, age) {this.name = namethis.age = age}sayHello() {console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`)}
}

(2)默认导出(Default Exports): 使用 export default 命令默认导出一个变量、函数、类。

默认导出变量

// 默认导出一个值
export default 20 // 导出一个对象作为默认值
const person = {name: 'Amy',age: 20,
}
export default person

默认导出函数

// 导出一个默认的加法函数
export default function add(a, b) {return a + b
}

默认导出类:

export default class Person {constructor(name, age) {this.name = namethis.age = age}sayHello() {console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`)}
}

2、导入(import)

(1)命名导入(Named Imports): 使用 import { xxx } from url 语法导入模块的指定变量、函数、或类。

export 导出的模块,在导入时不能随意取别名,名称必须与模块导出时相同!并且要使用类似于解构赋值的 {} 形式。

// 命名导出
export const name = 'Amy'
export function sayHello() {console.log('Hello!')
}// ----------------------------------------
// 命名导入
import { name, sayHello } from './module.js'

(2)默认导入(Default Imports): 使用 import xxx from url 语法导入模块的默认导出变量、函数、或类。

export default 导出的模块,在导入时可以取任意名称。并且 import 命令后面,不需要使用大括号。

// 默认导出
const age = 18
export default age// ---------------------------------------------
// 默认导入
import age from './module.js'

(3)整体导入: 用星号 * 指定一个对象,所有输出值都加载在这个对象上面。

将同一文件里的所有模块导入到一个对象中,不仅对 export 有效,同时对 export default 也同样有效。

// 整体导入
import * as Obj from './module.js'
console.log(Obj) // 见图片
console.log(Obj.fn) // ƒ fn() {}
console.log(Obj.className) // class className {}
console.log(Obj.age) // 18
// export default 也同样有效:imObj.default

在这里插入图片描述

(4)同时导入

当我们需要分别导入 export default 和 export 时,可以使用同时导入的方式。

// 我们可以分开实现
import { fn, className, age } from './module.js'
import sex from './module.js'
// 更推荐使用同时导入的方式
import sex, { fn, className, age } from './module.js'
// 注意:export default 必须在 export 之前

3、导出导入时起别名

export 导出的变量或 import导入的变量,可以使用 as 关键字重命名。

// 导出
function fn() {}
class className {}
const age = 18
export { fn as func, className as cN, age }
// 导入
import { func, cN, age as nl } from './module.js'
console.log(func) // ƒ fn() {}
console.log(cN) // class className {}
console.log(nl) // 18

4、export 与 import 的复合写法

如果在一个模块之中,先输入后输出同一个模块,import 语句可以与 export 语句写在一起。

export { foo, bar } from 'my_module'// 可以简单理解为
import { foo, bar } from 'my_module'
export { foo, bar }

上面代码中,export和import语句可以结合在一起,写成一行。但需要注意的是,写成一行以后,foo和bar实际上并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo和bar。

模块的接口改名和整体输出,也可以采用这种写法。

// 接口改名
export { foo as myFoo } from 'my_module'// 整体输出
export * from 'my_module'

默认接口的写法如下。

export { default } from 'foo'

具名接口改为默认接口的写法如下。

export { es6 as default } from './someModule'// 等同于
import { es6 } from './someModule'
export default es6

同样地,默认接口也可以改名为具名接口。

export { default as es6 } from './someModule'

ES2020 之前,有一种 import 语句,没有对应的复合写法。

import * as someIdentifier from 'someModule'

ES2020 补上了这个写法。

export * as ns from "mod";// 等同于
import * as ns from 'mod'
export { ns }

5、export 与 import 的总结

在 ES6 中使用 export、和 export default 向外导出成员; 使用 import 来导入成员。

在一个模块中,可以同时使用 export default 和 export 向外导出成员;export default 只允许向外导出一次。使用 export default 向外暴露的成员,可以用任意变量接收。使用 export 向外暴露的成员,必须用 {} 接收,变量之间用逗号分隔,且名称必须与导出时的名称一致。export 可以向外暴露多个成员,如果某些成员,在 import 导入时,不需要,可以不在 {} 中定义export 导出的变量或 import导入的变量,可以使用 as 关键字重命名。

6、import() 动态导入

import() 是 ES6 中的动态导入语法,它允许在运行时动态地加载模块。与传统的静态导入(使用 import 关键字:import 命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行。)相比,动态导入可以根据需要按需加载模块,提供了更大的灵活性。

// 静态导入:语法错误(import 和 export 命令只能在模块的顶层,不能在代码块之中)
if (x === 2) {import MyModual from './myModual'
}

import 函数的参数 specifier,指定所要加载的模块的位置。import 命令能够接受什么参数,import() 函数就能接受什么参数,两者区别主要是后者为动态加载。

// 动态导入
import(specifier)

import() 返回一个 Promise 对象,因此可以使用 async/await 等方式来处理导入的模块。

适用场合

(1)按需加载:import() 可以在需要的时候,再加载某个模块。

// 只有用户点击了按钮,才会加载 dialogBox 模块
button.addEventListener('click', event => {import('./dialogBox.js').then(dialogBox => {dialogBox.open()}).catch(error => {/* Error handling */})
})

(2)条件加载:import() 可以放在 if 代码块,根据不同的情况,加载不同的模块。

if (condition) {import('moduleA').then(...)
} else {import('moduleB').then(...)
}

(3)动态的模块路径:import() 允许模块路径动态生成。

import(f()).then(...)

动态导入的优点

可以根据需要按需加载模块,避免一次性加载所有模块,提高性能和加载速度。可以在条件满足时才加载模块,实现延迟加载和懒加载的效果。可以动态地根据运行时信息选择不同的模块进行加载。

三、ES6 Module 和 CommonJS 模块的区别

ES6 Module 是 JavaScript 的官方模块系统,而 CommonJS 是 Node.js 的模块系统。ESM 具有更强大的特性和更高的效率,适用于现代浏览器环境和某些前端工具链中。而 CJS 则适用于 Node.js 环境和一些较老的浏览器环境。然而,随着 Node.js 对 ESM 的支持不断改进,ESM 已经成为了通用的模块系统,并逐渐取代了 CJS 的使用。

1、语法差异

CommonJS 使用 module.exports = {} 导出一个模块对象,require(‘file_path’) 引入模块对象。

ES6 Module 使用 import 和 export 关键字来导入和导出模块。

2、加载方式

CommonJS 在运行时同步加载模块。它会先加载整个模块,然后再执行模块代码。

ES6 Module 在解析阶段进行静态分析,即在编译时确定模块依赖关系。它使用异步加载模块的方式,在运行时按需加载模块。

3、输出差异

CommonJS 模块中,module.exports 导出的是一个值的拷贝。当其他模块使用 require 导入该模块时,会得到这个拷贝的值,而不是原始值本身。因此,如果在被导入的模块内部对导出的值进行修改,不会影响到其他模块中已经导入的值。

// module.js
let count = 0setTimeout(() => {count++
}, 1000)module.exports = count// main.js
const count = require('./module')setTimeout(() => {console.log(count) // 输出: 0,因为count只是module.js导出的初始值的一个拷贝,不会变化
}, 2000)

ES6 Module 模块中,export 导出的是一个值的引用。当其他模块使用 import 导入该模块时,得到的是原始值的引用。这意味着,如果在被导入的模块内部对导出的值进行修改,会直接影响到其他导入该模块的地方,因为它们引用同一个原始值。

// module.js
export let count = 0setTimeout(() => {count++
}, 1000)// main.js
import { count } from './module'setTimeout(() => {console.log(count) // 输出: 1,因为count是module.js导出的原始值的引用,会随着变化而变化
}, 2000)

需要注意的是,虽然 ES6 模块的输出是引用,但并不意味着你可以直接修改导入的值。在严格模式下,对于 import 导入的值是只读的,不能直接修改。如果你想要修改导入的值,可以通过修改原始值或者使用 export default 来实现。

4、导入和导出特性

CommonJS 只支持默认导出,通过给 module.exports 赋值来导出模块。

ES6 Module 支持命名导出(Named Exports)和默认导出(Default Exports)两种导出方式。

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

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

相关文章

【vue/uniapp】使用 uni.chooseImage 和 uni.uploadFile 实现图片上传(包含样式,可以解决手机上无法上传的问题)

引入: 之前写过一篇关于 uview 1.x 版本上传照片 的文章,但是发现如果是在微信小程序的项目中嵌入 h5 的模块,这个 h5 的项目使用 u-upload 的话,图片上传功能在电脑上正常,但是在手机的小程序上测试就不会生效&#x…

漏洞复现--海康威视IP网络对讲广播系统远程命令执行

免责声明: 文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

职场革命:六款AI助手改写工作效率的故事

引言 在数字化时代,AI助手正快速成为职场的革命者。这些智能助手不仅仅是效率的提升者,它们更是创新的驱动力,重新定义了我们的工作方式。从自动化PPT创建到智能邮件优化,它们的影响深远且多元。本文将深入探讨六款不同领域的AI助…

三维模型数据的几何坐标变换的点云重建并行计算技术方法分析

三维模型数据的几何坐标变换的点云重建并行计算技术方法分析 倾斜摄影三维模型数据的几何坐标变换与点云重建并行计算技术的探讨主要涉及以下几个方面: 1、坐标系定义与转换:在进行坐标变换前,需要确定各个参考系的定义并实现坐标系之间的转…

卷积神经网络|制作自己的Dataset

在编写代码训练神经网络之前,导入数据是必不可少的。PyTorch提供了许多预加载的数据集(如FashionMNIST),这些数据集 子类并实现特定于特定数据的函数。 它们可用于对模型进行原型设计和基准测试,加载这些数据集是十分…

阿里云服务器8080端口安全组开通图文教程

阿里云服务器8080端口开放在安全组中放行,Tomcat默认使用8080端口,8080端口也用于www代理服务,阿腾云atengyun.com以8080端口为例来详细说下阿里云服务器8080端口开启教程教程: 阿里云服务器8080端口开启教程 阿里云服务器8080端…

SkyWalking 快速入门

SkyWalking 是一个基于 Java 开发的分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。 一、SkyWalking 简介 SkyWalking 是观察性分析平台和应用性能管理系统。 提供分布式追踪、服务网格…

输入输出流

1.输入输出流 输入/输出流类:iostream---------i input(输入) o output(输出) stream:流 iostream: istream类:输入流类-------------cin:输入流类的对象 ostream类…

使用Tensorboard可视化网络结构(基于pytorch)

前言 我们在搭建网络模型的时候,通常希望可以对自己搭建好的网络模型有一个比较好的直观感受,从而更好地了解网络模型的结构,Tensorboard工具的使用就给我们提供了方便的途径 Tensorboard概况 Tensorboard是由Google公司开源的一款可视化工…

【大模型+编程助手】国内编程助手安装与使用(CodeGeeX,Baidu Comate)

百度 Comate (可试用):https://comate.baidu.com/ 清华CodeGeeX (开源,暂时免费):https://codegeex.cn/ 华为:https://devcloud.cn-north-4.huaweicloud.com/codeartside/home?productsnap# 开发平台VScod…

贪吃蛇C语言实现(有源码)

前言 之前学了一点easyx图形库的使用&#xff0c;掌握一些基本用法后就用贪吃蛇来进行实战了&#xff0c;运行视频放在csdn视频那一栏了&#xff0c;之前的烟花也是。 1.头文件 #define _CRT_SECURE_NO_WARNINGS 1 #include<easyx.h> #include<conio.h> #includ…

【Vue2+3入门到实战】(21)认识Vue3、使用create-vue搭建Vue3项目、熟悉项目和关键文件

目录 一、认识Vue31. Vue2 选项式 API vs Vue3 组合式API2. Vue3的优势 二、 使用create-vue搭建Vue3项目1. 认识create-vue2. 使用create-vue创建项目 三、 熟悉项目和关键文件四、总结 一、认识Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script> export default {…

力扣题:高精度运算-1.2

力扣题-1.2 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;415. 字符串相加 解题思想&#xff1a;从后往前遍历两个字符串,然后进行相加即可 class Solution(object):def addStrings(self, num1, num2):""":type num1: str:type …

Navicat 技术干货 | 如何查看关系型数据库(MySQL、PostgreSQL、SQL Server、 Oracle)查询的运行时间

在数据库优化中&#xff0c;理解和监控查询运行时间是至关重要的。无论你是数据库管理员、开发人员或是参与性能调优的人员&#xff0c;知道如何查看查询运行时间能为你的数据库操作提供有价值的参考。本文中&#xff0c;我们将探索几款热门的关系数据库&#xff08;如 MySQL、…

ubuntu下快速安装使用docker

一、ubuntu下安装docker 1、命令行终端内直接输入docker 可以看到安装docker的命令提示 2、安装需要注意的几个点 (1)需要管理员权限 (2)更新软件源后再进行安装 命令行输入命令 sudo apt-get update #更新软件源 sudo apt install docker.io #安装docker 如图所示 二…

PostgreSQL荣获DB-Engines 2023年度数据库

数据库流行度排名网站 DB-Engines 2024 年 1 月 2 日发布文章宣称&#xff0c;PostgreSQL 荣获 2023 年度数据库管理系统称号。 PostgreSQL 在过去一年中获得了比其他 417 个产品更多的流行度增长&#xff0c;因此获得了 2023 年度 DBMS。 DB-Engines 通过计算每种数据库 2024 …

性能优化-OpenMP基础教程(一)

本文主要介绍OpenMP并行编程技术&#xff0c;编程模型、指令和函数的介绍、以及OpenMP实战的几个例子。希望给OpenMP并行编程者提供指导。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&am…

Mysql count统计去重的数据

不去重&#xff0c;是4 &#xff1a; SELECT COUNT(NAME) FROM test2 明显里面包含了2个 name 等于 mike的数据&#xff0c; 所以需要做去重 &#xff1a; 通过结合 count 函数和 DISTINCT 关键字 SELECT COUNT(DISTINCT NAME) FROM test2 好了就到这。

消息中间件 —— ActiveMQ 使用及原理详解

目录 一. 前言 二. JMS 规范 2.1. 基本概念 2.2. JMS 体系结构 三. ActiveMQ 使用 3.1. ActiveMQ Classic 和 ActiveMQ Artemis 3.2. Queue 模式&#xff08;P2P&#xff09; 3.3. Topic 模式&#xff08;Pub/Sub&#xff09; 3.4. 持久订阅 3.5. 消息传递的可靠性 …

数模学习day06-主成分分析

主成分分析(Principal Component Analysis,PCA)主成分分析是一种降维算法&#xff0c;它能将多个指标转换为少数几个主成分&#xff0c;这些主成分是原始变量的线性组合&#xff0c;且彼此之间互不相关&#xff0c;其能反映出原始数据的大部分信息。一般来说当研究的问题涉及到…