10

module.exports和exports,应该用哪个 - chuckQu

 1 year ago
source link: https://www.cnblogs.com/chuckQu/p/17655380.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在 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, '[email protected]');

console.log(jim.getUserStats());

代码输出如下:

Name: Jim
Age: 37
Email: [email protected]

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 中使用模块,并帮助你揭开模块语法的神秘面纱。

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK