JavaScript模块的导出和导入之export和module.exports的区别
export和module.exports
(需要前面的export没有“s”,后面的module.exports 有“s”)
使用两者根本区别是
**exports **返回的是模块函数
**module.exports **返回的是模块对象本身,返回的是一个类
使用上的区别是
exports的方法可以直接调用
module.exports需要new对象之后才可以调用
在js编程中经常会有模块的导出导入,涉及到一些导入导出关键字
- 导出关键字
- module.exports
- exports
- export
- export default
- 导入关键字
- require
- const xxx = require("模块名")
- import
- import { xxx } from "模块名"
- import xxx from "模块名"
- import xxx1, {xxx2, xxx3,...} from "模块名"
- import * from "模块名"
- require
因为在实际开发中经常会混淆这些用法,所以想要弄清楚这些的区别,让自己明白自己到底在写什么。本文作为学习笔记输出。
模块规范
JS模块化编程分了两种规范:CommonJS模块规范和ES6模块规范。
- CommonJS模块规范 —— CommonJS规范中,以module.exports导出接口,以require引入模块
- ES6模块规范 —— ES6标准规范中,以export指令导出接口,以import引入模块
在Node.js编程中,Node模块系统遵循的是CommonJS规范。
CommonJS模块规范
CommonJS规范规定: 每个js文件就是一个模块,有自己的作用域。
在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
如果要暴露给其他程序,需要以module.exports导出接口,以require引入模块。
module.exports 和 exports
module.exports / exports: 只有 Node 支持的导出
模块导出的时候,导出的是module.exports,不是exports
module.exports可以导出所有的类型。对象,函数,字符串、数值等。
每一个js文件通过node执行时,都自动创建一个module变量和一个exports变量。
module变量代表当前模块。这个变量是一个对象,同时,module对象会创建一个叫exports的属性(即module.exports),该属性初始化的值是 {},是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。
//logtes.js
console.log("我是外部js,没有使用export")
console.log(module)
执行node test1.js的打印结果:
path: 'C:\\Users\\xxwang\\Documents\\pmms\\TS\\tsdemo\\day01', exports: {}, filename: 'C:\\Users\\xxwang\\Documents\\pmms\\TS\\tsdemo\\day01\\logtes.js',loaded: false, children: [], paths: [ 'C:\\Users\\xxwang\\Documents\\pmms\\TS\\tsdemo\\day01\\node_modules', 'C:\\Users\\xxwang\\Documents\\pmms\\TS\\tsdemo\\node_modules', 'C:\\Users\\xxwang\\Documents\\pmms\\TS\\node_modules', 'C:\\Users\\xxwang\\Documents\\pmms\\node_modules', 'C:\\Users\\xxwang\\Documents\\node_modules', 'C:\\Users\\xxwang\\node_modules', 'C:\\Users\\node_modules', 'C:\\node_modules' ]
} Process finished with exit code 0
默认exports变量是对module.exports的引用,即exports和module.exports指向同一个内存块。 这等同在每个模块头部,有一行这样的命令。
var exports = module.exports;
- 当通过exports去改变内存块里内容时,module.exports的值也会改变
- 当通过module.exports去改变内存块里内容时,exports的值也会改变
- 当module.exports被改变的时候,exports不会被改变
- 当exports被改变的时候,module.exports不会被改变
所以,exports属性的出现应该可以直接向exports对象添加方法,从而方便对外输出模块接口。不过当module.exports改变时,exports与module.exports也就断开了链接,所以最好不要采用这种方式,统一采用module.exports方式。
// module_export_demo.js
module.exports.a = 100
console.log("log1: " + exports.a) // log1: 100exports.a = 200;
console.log("log2: " + module.exports.a) // log2: 200module.exports = "hello"
console.log("log3: " + JSON.stringify(exports)) // log3: {"a":200}
复制代码
module.exports可以导出所有的类型。对象,函数,字符串、数值等。 语法示例:
// module_export_demo2.js
var x = 5var str = "hello"var addX = function (value) {return value + x
};class Point {constructor(x, y) {this.x = x;this.y = y;}toString() {return '(' + this.x + ', ' + this.y + ')';}
}// module.exports.x = x
// module.exports.str = str
// module.exports.addX = addX
// module.exports.Point = Pointmodule.exports = {x: x,str: str,addX: addX,Point: Point
}// require时对比下两种方式x的值到底取哪个
exports = {x: 10,
}
复制代码
require
requirer用于加载模块,是node的一个全局方法,使用非常简单
const xxx = require("模块名")
复制代码
读入并执行一个JavaScript文件,返回模块的exports对象。如果没有发现指定模块,会报错。
require方法接受以下几种参数的传递:
- 原生模块,如http、fs、path等
- 相对路径的文件模块,如./mod或../mod
- 绝对路径的文件模块,如 /pathtomodule/mod
- 第三方模块,如koa等
在模块目录中通常有一个package.json文件,并且将入口文件写入main字段
// package.json{ "name" : "some-library","main" : "./lib/some-library.js" }
复制代码
require发现参数字符串指向一个目录以后,会自动查看该目录的package.json文件,然后加载main字段指定的入口文件。
如果package.json文件没有main字段,或者根本就没有package.json文件,则会加载该目录下的index.js文件或index.node文件
因为模块导出的实际是module.exports,所以require只能看到通过 module.exports 导出的内容,看不到通过exports导出的内容。它相当于module.exports的传送门,module.exports后面的内容是什么,require的结果就是什么,对象、数字、字符串、函数...再把require的结果赋值给某个变量。 针对上面的 module_export_domo2.js 文件,引入模块示例
// node require_demo2.js
const demo2 = require("./module_export_demo2")console.log(demo2.x) // 5 也证明了引入的是module.export的内容
console.log(demo2.str) // hello
console.log(demo2.addX(15)) // 20 = 5 + 15 let point = new demo2.Point(3, 4)
console.log(point.toString()) // (3, 4)
复制代码
require 是运行时的,其参数可以是表达式
let value = 2
const demo2 = require("./module_export" + "_demo" + value)
复制代码
require函数加载模块
-
require函数加载模块顺序按照其在代码中出现的顺序
-
require函数加载模块是同步的,只有加载完成,才能执行后面的操作
-
require函数加载的模块是被输出的值的拷贝,不会受到模块内容变化影响
// module_export_demo3.jsvar counter = 3;function incCounter() {counter++;}module.exports = {counter: counter,incCounter: incCounter,}; 复制代码const demo3 = require("./module_export_demo3")console.log(demo3.counter); // 3demo3.incCounter();console.log(demo3.counter); // 3 复制代码counter输出结果说明module_export_demo3模块内部的变化就影响不到counter了
-
模块第一次被加载时会执行一次,后续被加载时不会再执行,都是从缓存中获取的
// module_export_demo3.js console.log("hello") module.exports = "wrold" 复制代码const demo3 = require("./module_export_demo3") const demo3_1 = require("./module_export_demo3") const demo3_2 = require("./module_export_demo3") const demo3_3 = require("./module_export_demo3") const demo3_4 = require("./module_export_demo3") const demo3_5 = require("./module_export_demo3") console.log(demo3) console.log(demo3_1)// hello // wrold // wrold 复制代码hello只会被打印一次说明console.log("hello")语句只执行了一次,module_export_demo3.js只被加载了一次。
ES6模块规范
ES6发布的module并没有直接采用CommonJS,甚至连require都没有采用,也就是说require仍然只是node的一个私有的全局方法,module.exports也只是node私有的一个全局变量属性,跟标准什么关系都没有。
ES6模块规范是,在创建JS模块时,export 语句用于从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们。
export 和 export default
ES6模块导出有两种方式:export(命名导出) 和 export default(默认导出)。 在导出多个值时,命名导出非常有用。在导入时,必须使用相应对象的相同名称。但是,可以使用任何名称导入默认导出。
export语法介绍
// 导出单个特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}// 导出列表
export { name1, name2, …, nameN };// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };// 默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };// 导出"引入模块的导出值"
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export * from …; // 导出"引入模块的所有导出值",不包括模块的默认导出值
export { default } from …; // 导出"引入模块的默认导出值"
复制代码
- export与export default均可用于导出常量、函数、文件、模块等
- 通过export方式导出,在导入时要加{ },export default则不需要
- 在一个文件中,export可以有多个,export default仅有一个
- 大部分风格建议,模块中最好在末尾用一个export导出所有的接口
export 1 // 这种写法错误// 正确的写法
const value = 1
export { value }// 或者
export const value = 1// 或者
const value = 1
export default value// 或者
export default 1
复制代码
export default是别名的语法糖,这个语法糖的好处在是
- import的时候,可以省去花括号{}。
- import的时候, 可以起任何变量名表示引入变量
所以如果import的时候,你发现某个变量没有花括号括起来(除了* 号),是因为该变量是通过export default 导出的。
// d.js
// 导出函数
export default function() {}// 等效于:
// function a() {};
// export {a as default};复制代码
import a from "d.js" // a 是 {defalut as a}的替代写法。
复制代码
所以使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名。
// a.js
let sex = "boy";
export default sex //sex不能加大括号 等价于 export {sex as default}
复制代码
本质上,a.js文件的export default输出一个叫做default的变量,然后系统允许你为它取任意名字。 自然default只能有一个值,所以一个文件内不能有多个export default。
// b.js
import any from "./a.js"
import any12 from "./a.js"
console.log(any, any12) // boy,boy
复制代码
import
require 和 import是完全不同的两种概念。require是赋值过程,import是解构过程 const xxx = require("模块名") import { xxx } from "模块名"
- import是编译时的, 必须放在文件开头,否则会报错
- import后面跟上花括号的形式是最基本的用法,花括号里面的变量与export后面的变量一一对应。
import {a} from ..
复制代码
- 支持给变量取别名。因为有的时候不同的两个模块可能有相同的接口,可以给这个变量取一个别名,方便在当前的文件里面使用。
import {a as a_a} from ..
复制代码
import介绍语法
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
var promise = import("module-name"); // 动态模块加载,返回的是一个promise对象
复制代码
Node为何支持export / import
我们经常会看到在node中也会用export / import,这是什么呢? 我们在node中使用babel支持ES6,仅仅是将ES6转码为ES5再执行,import语法会被转码为require。因为目前所有的引擎都还没有实现export / import。
如何让Node.js支持ES6的语法具体参考在node环境中支持ES6代码
// ES6语法
import {a} from "./demo.js"
// 转码ES5后
var _demo = require("./demo.js")
复制代码
这也是为什么在使用module.exports模块导出时,在引入模块时使用import仍然起效,因为本质上,import会被转码为require去执行。
总结
CommonJS规范中,建议尽量都用 module.exports 导出,然后用require导入 ES6规则中,大部分风格建议,模块中最好在末尾用一个export导出所有的接口
- module.exports / exports: 只有 Node 支持的导出
- require: Node 和 ES6 都支持的引入
- export / import : 只有ES6 支持的导出引入
相关文章:
JavaScript模块的导出和导入之export和module.exports的区别
export和module.exports (需要前面的export没有“s”,后面的module.exports 有“s”) 使用两者根本区别是 **exports **返回的是模块函数 **module.exports **返回的是模块对象本身,返回的是一个类 使用上的区别是exports的方法可以直接调用module.exports需要new…...
基于朴素贝叶斯分类器的钞票真伪识别模型
基于朴素贝叶斯分类器的钞票真伪识别模型 内容 本实验通过实现钞票真伪判别案例来展开学习朴素贝叶斯分类器的原理及应用。 本实验的主要技能点: 1、 朴素贝叶斯分类器模型的构建 2、 模型的评估与预测 3、 分类概率的输出 源码下载 环境 操作系统…...
【Python】【进阶篇】二十二、Python爬虫的BS4解析库
目录二十二、Python爬虫的BS4解析库22.1 BS4下载安装22.2 BS4解析对象22.3 BS4常用语法1) Tag节点22.4 遍历节点22.5 find_all()与find()1) find_all()2) find()22.6 CSS选择器二十二、Python爬虫的BS4解析库 Beautiful Soup 简称 BS4(其中 4 表示版本号࿰…...
UDS统一诊断服务【五】诊断仪在线0X3E服务
文章目录前言一、诊断仪在线服务介绍二、数据格式2.1,请求报文2.2,子功能2.3,响应报文前言 本文介绍UDS统一诊断服务的0X3E服务,希望能对你有所帮助 一、诊断仪在线服务介绍 诊断仪在线服务比较简单,其功能就是告诉服…...
我的创作纪念日:Unity CEO表示生成式AI将是Unity近期发展重点,发布神秘影片预告
PICK 未来的AI技术将会让人类迎来下一个生产力变革,这其中也包括生成型AI的突破性革新。各大公司也正在竞相推出AIGC工具,其中微软的Copilot、Adobe的Firefly、Github的chatGPT等引起了人们的关注。然而,游戏开发领域似乎还没有一款真正针对性…...
秩亏自由网平差的直接解法
目录 一、原理概述二、案例分析三、代码实现四、结果展示一、原理概述 N = B T P B N=B^TPB N=<...
大数据开发必备面试题Spark篇合集
1、Hadoop 和 Spark 的相同点和不同点? Hadoop 底层使用 MapReduce 计算架构,只有 map 和 reduce 两种操作,表达能力比较欠缺,而且在 MR 过程中会重复的读写 hdfs,造成大量的磁盘 io 读写操作,所以适合高时…...
C ++匿名函数:揭开C++ Lambda表达式的神秘面纱
潜意识编程:揭秘C Lambda表达式的神秘面纱 Subconscious Programming: Unveiling the Mystery of C Lambda Expressions 引言:Lambda表达式的魅力 (The Charm of C Lambda Expressions)Lambda表达式简介与基本概念 (Introduction and Basic Concepts of …...
AOP使用场景记录总结(缓慢补充更新中)
测试项目结构: 目前是测试两个日志记录和 代码的性能测试 后面如果有其他的应用场景了在添加.其实一中就包括了二,但是没事,多练一遍 1. 日志记录 比如说对service层中的所有增加,删除,修改方法添加日志, 记录内容包括操作的时间 操作的方法, 方法的参数, 方法所在的类, 方法…...
FPGA基于XDMA实现PCIE X4的HDMI视频采集 提供工程源码和QT上位机程序和技术支持
目录1、前言2、我已有的PCIE方案3、PCIE理论4、总体设计思路和方案5、vivado工程详解6、驱动安装7、QT上位机软件8、上板调试验证9、福利:工程代码的获取1、前言 PCIE(PCI Express)采用了目前业内流行的点对点串行连接,比起 PCI …...
ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析
查看原文>>>ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析 目录 专题一、空间数据获取与制图 专题二、ArcGIS专题地图制作 专题三、空间数据采集与处理 专题四、遥感数据处理与应用 专题五、DEM数据…...
怎么找回回收站里已经删除的文件
作为忙忙碌碌的打工人,电脑办公是在所难免的,而将使电脑存储着大量的数据文件,不少小伙伴都养成了定期清理电脑的习惯。而清理简单快捷的方法,无疑是直接把文件拖进回收站里。再一键清空,清理工作就完成了。但如果发现…...
Spring Boot、Cloud、Alibaba 版本说明
Spring Boot、Cloud、Alibaba 版本说明 一、毕业版本依赖关系(推荐使用) 由于 Spring Boot 3.0,Spring Boot 2.7~2.4 和 2.4 以下版本之间变化较大,目前企业级客户老项目相关 Spring Boot 版本仍停留在 Spring Boot 2.4 以下,为了同时满足存…...
软件测试入门第一步:编写测试报告
什么是测试报告? 1、说明:是指把测试的过程和结果写成文档,对发现的问题和缺陷进行分析,为纠正软件的存在的质量问题提供依据,同时为软件验收和交付打下基础。 ps. 【测试过程和测试结果的分析报告,以及上线…...
【Vue】vue中的路由导航守卫(路由的生命周期)
文章目录全局前置守卫可选的第三个参数 next全局解析守卫router.beforeResolve全局后置钩子路由独享的守卫组件内的守卫可用的配置 API使用组合 API完整的导航解析流程正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入…...
NumPy 基础知识 :6~10
原文:Numpy Essentials 协议:CC BY-NC-SA 4.0 译者:飞龙 六、NumPy 中的傅立叶分析 除其他事项外,傅立叶分析通常用于数字信号处理。 这要归功于它在将输入信号(时域)分离为以离散频率(频域&am…...
实现vue的条件渲染
我的需求是根据设备不同的状态 渲染不同的标签。设备状态用device_State表示。 在线上面是一个vue的标签,我有一个数据state ,如何让这个标签根据数据的取值 ,修改内容,如state1时,标签修改为离线 要根据数据的取值动态…...
第四章 word2vec 的高速化
目录4.1 word2vec 的改进①4.1.1 Embedding 层4.1.2 Embedding 层的实现4.2 word2vec 的改进②4.2.1 中间层之后的计算问题4.2.2 从多分类到二分类4.2.3 sigmoid 函数和交叉熵误差4.2.4 多分类到二分类的实现4.2.5 负采样4.2.6 负采样的采样方法4.2.7 负采样的实现4.3 改进版 w…...
【四】3D Object Model之创建Creation——clear_object_model_3d()/copy_object_model_3d()算子
😊😊😊欢迎来到本博客😊😊😊 🌟🌟🌟 Halcon算子太多,学习查找都没有系统的学习查找路径,本专栏主要分享Halcon各类算子含义及用法,有…...
第三十一章 配置镜像 - 删除镜像成员时删除镜像数据库属性
文章目录第三十一章 配置镜像 - 删除镜像成员时删除镜像数据库属性删除镜像成员时删除镜像数据库属性编辑或删除异步成员第三十一章 配置镜像 - 删除镜像成员时删除镜像数据库属性 删除镜像成员时删除镜像数据库属性 当从镜像中删除成员时,始终可以选择从属于该镜…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
