这个 Node.js exports\require 语句究竟是如何工作的?

How exactly works this Node.js exports\require staatements?

总的来说,我对 nodeJS 和 JS 技术还很陌生(我来自 Java)。 我正在编写以下简单代码,我对 require 语句的实际工作方式有以下疑问:

我有这个文件包含一些 mocha 测试代码:

const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');       // It is a constructor

const web3 = new Web3(ganache.provider());

const { interface, bytecode } = require('../compile');

let accounts;
let inbox;


beforeEach(async () => {
    // Get a list of all accounts:
    accounts = await web3.eth.getAccounts()         // use the web3 module to interact with ETH cryupto
       
    // Use one of these accounts to deploy the contract:
    inbox = await new web3.eth.Contract(JSON.parse(interface))
                    .deploy({ data: bytecode, arguments: ['Hi there!'] })
                    .send({ from: accounts[0], gas: '1000000' })
});

describe('Inbox', () => {
    it('depploys a contract', () => {
        console.log(accounts);
        console.log(inbox);
    });
});

如你所见,我有这一行:

const { interface, bytecode } = require('../compile');

据我所知,它正在创建一个 JS 对象(如果我做错了断言,请纠正我)包含 ../compile“模块检索的两个字段"(里面编译一个模块?)

这里我有以下疑惑:我想这与我在父文件夹中的 compile.js 文件有关(与 mocha 相关的父文件脚本文件夹)。此 compile.js 文件夹包含以下代码:

const path = require('path');
const fs = require('fs');
const solc = require('solc');

const inboxPath = path.resolve(__dirname, 'contracts', 'Inbox.sol');
const source = fs.readFileSync(inboxPath, 'utf-8');


console.log(solc.compile(source, 1).contracts[':Inbox']);    
module.exports = solc.compile(source, 1).contracts[':Inbox'];

我唯一能想到的是这个 solc.compile(source, 1).contracts[':Inbox'] 是一个包含一些字段的对象,包括这些 interfacebytcode 字段。

所以如果我很好地理解它应该以这种方式工作:

但是 require() 语句的这个用户究竟意味着什么?意思是:取compile.js文件导出的内容?如果是这样,导出的是 JavaScript 对象,其中包含这些 interfacebytcode 字段,这些字段被设置为 const.

它是正确的还是我遗漏了什么?

您可能需要阅读 CommonJS 模块的文档:

https://nodejs.org/dist/latest-v16.x/docs/api/modules.html

它为您列出了 require() 的作用。

是的,你是对的。它 returns 无论 module.exports 定义为什么,您都可以像分配任何变量一样分配它。默认情况下它是 {},一个空对象。但是如果我想导出一个函数,我会这样做:

module.exports.myFunc = function(a){
  console.log(a);
}

现在 module.exports 的值为 {myFunc: Function()}。所以当我从另一个文件导入模块时:

const myFile = require('./myFile');
myFile.myFunc("Hello there!"); //Prints: Hello there!

当您在大括号内按名称获得函数时,您正在解构 对象,请查看MDN Web Docs。因此,当您拥有 const { interface, bytecode } = require("../compile"); 时,您将获得 compile 模块的 interfacebytecode 属性。所以你是对的,那就是:

solc.compile(source, 1).contracts[':Inbox'];

的字段包括 interfacebytecode

{
  interface: Function(),
  bytecode: Function()
}

如果导入时未解构 require 语句,则可以像引用任何其他对象一样引用其属性。

const compile = require("../compile");
compile.interface();
compile.bytecode();

您可以将 module.exports 设置为任何内容,一个字符串,一个 class,一个函数。例如,如果您在 myFile.js 中导出一个字符串:module.exports = "foobar";,并且导入文件:

const myFile = require("./myFile");
console.log(myFile); //Prints: foobar