在 Node.js 编程中,模块是独立的功能单元,可以在项目间共享和重用。作为开发人员,模块让我们的生活更轻松,因为我们可以使用模块来增强应用程序的功能,而无需亲自编写。它们还允许我们组织和解耦代码,从而使应用程序更易于理解、调试和维护。

在这篇文章中,我将介绍如何在 Node.js 中使用模块,重点是如何导出和消费它们。

各种模块格式

由于 JavaScript 最初没有模块的概念,因此随着时间的推移,出现了各种相互竞争的格式。下面列出了需要注意的主要格式:

  • Asynchronous Module Definition (AMD)格式用于浏览器,使用define函数来定义模块。
  • CommonJS (CJS)格式用于Node.js,使用requiremodule.exports来定义依赖和模块。npm 生态系统就是基于这种格式构建的。
  • ES Module (ESM)格式。从 ES6(ES2015)开始,JavaScript 支持原生模块格式。它使用 export 关键字导出模块的公共 API,使用 import 关键字导入模块。
  • System.register格式用于支持 ES5 中的 ES6 模块。
  • Universal Module Definition (UMD)格式可以用于浏览器和Node.js。当一个模块需要被多个不同的模块加载器导入时,它就会非常有用。

请注意,本文仅涉及 Node.js 的标准 CommonJS格式。

引入模块

Node.js带来了一系列内置模块,这样我们就可以直接在代码中使用而不需要安装它们。要使用它们,我们需要使用require关键字引入模块,并赋值给变量。然后就可以用它来调用模块公开的任何方法。

举个例子,要罗列出目录下的内容,可以使用文件系统模块,以及该模块的readdir方法:

const fs = require('fs');
const folderPath = '/home/jim/Desktop/'; fs.readdir(folderPath, (err, files) => {
files.forEach(file => {
console.log(file);
});
});

请注意,在 CommonJS 中,模块是同步加载的,并按照模块出现的顺序进行处理。

创建并导出模块

现在,让我们看看如何创建自己的模块并导出它。创建user.js文件并添加下列代码:

const getName = () => {
return 'Jim';
}; exports.getName = getName;

然后在同一文件夹下创建index.js,并添加下列代码:

const user = require('./user');
console.log(`User: ${user.getName()}`);

使用node index.js运行代码,你会在终端上看到下列输出:

User: Jim

发生了啥?好吧,如果你查看user.js文件,你会注意到我们定义了一个getName函数,然后使用exports关键字让它在任意导入的地方可用。在index.js中,我们导入了该函数并执行了它。还需要注意require语句,该模型名称有着./前缀,意味着它是本地文件。还要注意的是,此处不需要添加文件扩展名。

导出多个方法和值

我们可以用同样的方式导出多个方法和值:

const getName = () => {
return 'Jim';
}; const getLocation = () => {
return 'Munich';
}; const dateOfBirth = '12.01.1982'; exports.getName = getName;
exports.getLocation = getLocation;
exports.dob = dateOfBirth;

index.js中这么使用:

const user = require('./user');
console.log(
`${user.getName()} lives in ${user.getLocation()} and was born on ${user.dob}.`
);

上述代码的产出是:

Jim lives in Munich and was born on 12.01.1982.

注意我们给导出的 dateOfBirth 变量起的名字可以是任何我们喜欢的名字(本例中为 dob)。它不必与原始变量名相同。

语法的变化

我还应该提到,可以在导出过程中导出方法和值,而不仅仅是在文件末尾导出。

举个例子:

exports.getName = () => {
return 'Jim';
}; exports.getLocation = () => {
return 'Munich';
}; exports.dob = '12.01.1982';

多亏了解构赋值,我们可以挑选想要导入的方法:

const { getName, dob } = require('./user');
console.log(
`${getName()} was born on ${dob}.`
);

导出默认值

上面的示例中,我们单独导出了函数和值。这对于整个应用程序都可能需要的辅助函数来说非常方便,但当你有一个只导出一样东西的模块时,使用 module.exports 会更常见:

class User {
constructor(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
} getUserStats() {
return `
Name: ${this.name}
Age: ${this.age}
Email: ${this.email}
`;
}
} module.exports = User;

index.js中:

const User = require('./user');
const jim = new User('Jim', 37, 'jim@example.com'); console.log(jim.getUserStats());

代码输出如下:

Name: Jim
Age: 37
Email: jim@example.com

module.exports和exports的区别

在开源世界里,你可以会遇到下列语法:

module.exports = {
getName: () => {
return 'Jim';
}, getLocation: () => {
return 'Munich';
}, dob: '12.01.1982',
};

在这里,我们将想要导出的函数和值分配给 module 上的 exports 属性,当然,这样做效果很好:

const { getName, dob } = require('./user');
console.log(
`${getName()} was born on ${dob}.`
);

那么,module.exportsexports的不同之处是什么?一个只是另一个的别名吗?

有点,但不完全是……

为了阐明我的意思,我们更改index.js中的代码,打印module的值:

console.log(module);

输出如下:

Module {
id: '.',
exports: {},
parent: null,
filename: '/home/jim/Desktop/index.js',
loaded: false,
children: [],
paths:
[ '/home/jim/Desktop/node_modules',
'/home/jim/node_modules',
'/home/node_modules',
'/node_modules' ] }

正如你看到的,module有一个exports属性。在exports上添加一些东西:

// index.js
exports.foo = 'foo';
console.log(module);

输出如下:

Module {
id: '.',
exports: { foo: 'foo' },
...

exports 分配的属性也会将它们添加到 module.exports。这是因为(至少最初)exports 是对 module.exports 的引用。

应该用哪个

由于 module.exportsexports 都指向同一个对象,因此使用哪个通常并不重要。例如:

exports.foo = 'foo';
module.exports.bar = 'bar';

这段代码将导致模块的导出对象为 { foo: 'foo', bar: 'bar' }

不过,有一个注意事项。无论你将什么赋值给 module.exports ,都将从你的模块中导出什么。

那么,请看下面的内容:

exports.foo = 'foo';
module.exports = () => { console.log('bar'); };

这样只会导出一个匿名函数。foo 变量将被忽略。

总结

模块已成为 JavaScript 生态系统不可或缺的一部分,它使我们能够将较小的部分组成大型程序。我希望本文能为你介绍如何在 Node.js 中使用模块,并帮助你揭开模块语法的神秘面纱。

以上就是本文的全部内容,如果对你有所帮助,欢迎点赞、收藏、转发~

module.exports和exports,应该用哪个的更多相关文章

  1. nodejs里的module.exports和exports的关系

    关于node里面的module.exports和exports的异同,网上已经有很多的资料,很多的文章,很多的博客,看了很多,好像懂了,又好像不懂,过几天又不懂了...大致总结是这样的: //下面这种 ...

  2. Node.js module.exports和exports的区别

    require 用来加载代码,而 exports 和 module.exports 则用来导出代码,从接触node.js就不会它们两陌生,上代码: foo.js exports.a = functio ...

  3. node基础再现--module.exports 和exports

    实际上,最最基础的方法,最最原始的方法是module.exports,至于exports,是为了方便书写才出来的,应该说,module.exports 包含exports,所工作的范围更加的广泛! m ...

  4. module.exports与exports,export和export default

    还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...

  5. nodejs里的module.exports和exports

    引 在node.js中我们可以使用module.exports和exports导出模块,设置导出函数.数组.变量等等 为什么可以用这两个模块? 或者直接问,node.js的模块功能是怎么实现的. 这样 ...

  6. module.exports与exports区别

    CommonJS模块规范 Node应用由模块组成,采用CommonJS模块规范. 根据这个规范,每个文件就是一个模块,有自己的作用域.在一个文件里面定义的变量.函数.类,都是私有的,对其他文件不可见. ...

  7. module.exports与exports

    API文档是枯燥的,下面本人收集了一些论坛经常有人疑问和开源代码中经常遇到的案例供大家研究一下. module.exports与exports的区别 每一个node.js执行文件,都自动创建一个mod ...

  8. node (02 CommonJs 和 Nodejs 中自定义模块)顺便讲讲module.exports和exports的区别 dependencies 与 devDependencies 之间的区别

    CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准的缺陷.它的终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库,而不只是停留在小脚本程序的阶 ...

  9. (转)Node.js module.exports与exports

    本文转自Node.js module.exports与exports 作者: chemdemo 折腾Node.js有些日子了,下面将陆陆续续记录下使用Node.js的一些细节. 熟悉Node.js的童 ...

  10. module.exports 与 exports

    module.exports 与 exports 注意:1 对于要导出的属性,可以简单直接挂到 exports 对象上2 对于类,为了直接使导出的内容作为类的构造器可以让调用者使用 new 操作符创建 ...

随机推荐

  1. el-table自适应列宽

    这里可对内容为文本的列进行自适应列宽 以下为 工具方法 /** * 使用span标签包裹内容,然后计算span的宽度 width: px * @param valArr */ function get ...

  2. Express实战个人订阅号实现网站登录

    今天我们来实现一个使用个人订阅号实现网站的功能,后端使用的是 express .其它框架原理基本一致,只是定义路由或返回响应数据部分代码跟 express 有所出入.先来一波效果图: 1. 前言 20 ...

  3. 金三银四抢人季,HR 如何 3 招做到效率为王?

    春招伊始,面对队伍庞大的校招人群,蜂拥而入的简历,HR 如何才能快速搞定呢?Bug君总结了一下过往招聘季的一些比较流行的环节: 通过线上宣讲,节省出行成本.时间,老板更认可了 现在大多数企业都会在直播 ...

  4. linux 递归和函数实验

    递归 作用:自己调用自己 1.例子:阶乘 2.遍历目录下所有文件 函数 1.函数能够接受一个参数,参数为用户名: 判断一个用户是否存在 如果存在,就返回此用户的shell 和 UID :并返回正常状态 ...

  5. CentOS Linux 7 安全基线设置

    作为一个生信人,不管是日常的数据分析还是其他工具应用的开发,服务器的安全始终是一个无法避免的话题.尤其是当我们拿到一台新的服务器,我们需要怎样才能确保它是安全可靠,并最小限度降低它被攻击的可能性? 下 ...

  6. Java 新的生态,Solon v2.3.2 发布

    Solon 是什么框架? 一个,Java 新的生态型应用开发框架.它从零开始构建,有自己的标准规范与开放生态(全球第二级别的生态).与其他框架相比,它解决了两个重要的痛点:启动慢,费资源. 解决痛点? ...

  7. 网站开发[1] - Spring Boot 快速建立项目

    前言 学校的数据库课程要求做出前端页面对数据库进行交互, 可以使用 Python 或者 Java 语言作为后端, Python语言使用起来非常方便, 但出于对自己的挑战以及更加贴合实际企业开发, 我选 ...

  8. k8s实战案例之部署redis单机和redis cluster

    1.在k8s上部署redis单机 1.1.redis简介 redis是一款基于BSD协议,开源的非关系型数据库(nosql数据库),作者是意大利开发者Salvatore Sanfilippo在2009 ...

  9. HTTP请求:requests的进阶使用方法浅析

    1 背景 上篇文章讲解了requests模块的基础使用,其中有get.put.post等多种请求方式,使用data.json等格式做为请求参数,在请求体中添加请求头部信息的常见信息,如:headers ...

  10. 微信小程序脚手架火爆来袭,集成 Taro、uniapp 第三方模版,支持小程序 CI 上传,预览,发布

    微信小程序脚手架 @wechat-mp/cli 微信小程序脚手架,集成 Taro.uniapp 第三方模版,支持小程序 CI 上传,预览,发布 注意事项 需要在微信公众平台开发管理-开发设置-IP白名 ...