在JavaScript和NodeJS中,“require”是什么意思?

712

我正在尝试让JavaScript读写PostgreSQL数据库。我在GitHub上找到了这个项目。我成功地在Node中运行了以下示例代码。

var pg = require('pg'); //native libpq bindings = `var pg = require('pg').native`
var conString = "tcp://postgres:1234@localhost/postgres";

var client = new pg.Client(conString);
client.connect();

//queries are queued and executed one after another once the connection becomes available
client.query("CREATE TEMP TABLE beatles(name varchar(10), height integer, birthday timestamptz)");
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['Ringo', 67, new Date(1945, 11, 2)]);
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['John', 68, new Date(1944, 10, 13)]);

//queries can be executed either via text/parameter values passed as individual arguments
//or by passing an options object containing text, (optional) parameter values, and (optional) query name
client.query({
  name: 'insert beatle',
  text: "INSERT INTO beatles(name, height, birthday) values($1, $2, $3)",
  values: ['George', 70, new Date(1946, 02, 14)]
});

//subsequent queries with the same name will be executed without re-parsing the query plan by postgres
client.query({
  name: 'insert beatle',
  values: ['Paul', 63, new Date(1945, 04, 03)]
});
var query = client.query("SELECT * FROM beatles WHERE name = $1", ['John']);

//can stream row results back 1 at a time
query.on('row', function(row) {
  console.log(row);
  console.log("Beatle name: %s", row.name); //Beatle name: John
  console.log("Beatle birth year: %d", row.birthday.getYear()); //dates are returned as javascript dates
  console.log("Beatle height: %d' %d\"", Math.floor(row.height/12), row.height%12); //integers are returned as javascript ints
});

//fired after last row is emitted
query.on('end', function() { 
  client.end();
});

接下来,我尝试在网页上运行它,但似乎没有任何反应。我在JavaScript控制台上检查了一下,它只是显示:
"Uncaught ReferenceError: require is not defined"
那么这个"require"是什么?为什么它在Node中可以工作,但在网页中却不行?
另外,在我让它在Node中工作之前,我必须执行"npm install pg"。这是怎么回事?我在目录中找不到pg文件。它把它放在哪里了,JavaScript又是如何找到它的?

72
require 不是 JavaScript 的一部分,它是在 nodejs 中使用的关键字。nodejs 不是你在客户端使用的 DOM。因此,一个可能在 nodejs 中工作的脚本可能在浏览器中无法正常工作。你能在 nodejs 中调用 window 或者 document 吗?不能。同样的道理也适用于在浏览器中使用 require。 - mpm
9
我该如何修改上述代码,以便在浏览器中运行? - neuromancer
9
从网页上无法直接与Pg进行通信。您需要能够打开一个纯的TCP/IP套接字,通过该套接字发送和接收二进制数据,而且没有任何Web浏览器可以让您这样做。您所提到的库是node.js的扩展,不适用于客户端JavaScript。我强烈建议您通过Web服务器和JSON请求/响应从客户端与您的PostgreSQL服务器通信。 - Craig Ringer
1
我正在本地运行PostgreSQL。为了搭建一个Web服务器,我需要安装什么? - neuromancer
1
Node?它是一个相当不错的Web服务器,或者可以成为一个,在本地安装。 - Timothy Meade
显示剩余3条评论
7个回答

1179
那么什么是“require”? require()不是JavaScript标准API的一部分。但在Node.js中,它是一个具有特殊目的的内置函数:加载模块
模块是一种将应用程序拆分为单独文件的方式,而不是将所有应用程序放在一个文件中。这个概念在其他语言中也存在,语法和行为略有不同,例如C的include,Python的import等。
Node.js模块与浏览器JavaScript之间的一个重要区别是如何从一个脚本的代码访问另一个脚本的代码。
  • 在浏览器JavaScript中,通过<script>元素添加脚本。当它们执行时,它们都可以直接访问全局范围,这是所有脚本之间的“共享空间”。任何脚本都可以自由地定义/修改/删除/调用全局范围上的任何内容。

  • 在Node.js中,每个模块都有自己的作用域。模块不能直接访问另一个模块中定义的东西,除非它选择将它们公开。要从模块中公开东西,必须将它们分配给exportsmodule.exports。对于一个模块访问另一个模块的exportsmodule.exports它必须使用require()

在您的代码中,var pg = require('pg');加载了pg模块,这是一个Node.js的PostgreSQL客户端。这使得您的代码可以通过变量pg访问PostgreSQL客户端API的功能。
为什么它在节点中工作而不在网页中?

require()module.exportsexports 是专为 Node.js 设计的模块系统的 API,浏览器不支持该模块系统。

另外,在我让它在 Node.js 中工作之前,我必须执行 npm install pg。这是怎么回事?

NPM 是一个提供 JavaScript 模块发布服务的包仓库。 npm install 是一个命令,可以从 NPM 的仓库下载包。

它把它放在哪里了,JavaScript 怎么找到它?

npm 命令行会把所有下载的模块放在你运行 npm install 的目录下的 node_modules 文件夹中。Node.js 有非常详细的文档,介绍了如何寻找其他模块,其中包括查找 node_modules 文件夹的过程。


16
我认为WebPack也有自己的require支持 - Benny Bottema
2
Node.js 为什么需要这个功能? - Melab
36
因为模块化在代码膨胀到大于大学编程练习并涉及多个人时是必需的。这就是为什么自从很久以前开始使用它们,比如Mesa编程语言。请注意我已经尽力使翻译更通俗易懂,但没有改变原意。 - David Tonhofer
4
在 PHP 中的等效操作是 include/require[_once]php.net 链接),而不是 use,后者是一个 别名 关键字。 - nevvermind
2
@juancarlospeñacabrera require 只返回 module.exports 在其文件中定义的内容。在你所指的情况下,require('socket.io') 返回一个函数,而 require('socket.io')(http) 将返回使用传递的 http 参数调用该函数的结果,并将其分配给 io :) - vegetable
显示剩余4条评论

125

首先,让我们区分在网页浏览器中的JavaScript和在服务器上的JavaScript(通常是CommonJS和Node)。

JavaScript是一种传统上被限制在网页浏览器中使用的语言,其全局上下文受到限制,主要由所谓的文档对象模型(DOM)Level 0(Netscape Navigator JavaScript API)定义。

服务器端JavaScript消除了这种限制,并允许JavaScript调用各种本地代码块(例如Postgres库)和打开套接字。

现在,require()是CommonJS规范中定义的一个特殊函数调用。在Node中,它解析节点搜索路径中的库和模块,通常在同一目录(或调用的JavaScript文件的目录)中定义为node_modules,或在系统范围内的搜索路径中。

为了解答你问题的其他部分,我们需要在运行在浏览器中的代码与数据库服务器之间使用代理。

既然我们正在讨论Node,并且您已经熟悉如何从那里运行查询,那么将Node用作代理似乎很合理。

作为一个简单的示例,我们将创建一个URL,根据给定的名称以JSON格式返回关于甲壳虫乐队成员的一些事实。

/* your connection code */

var express = require('express');
var app = express.createServer();
app.get('/beatles/:name', function(req, res) {
    var name = req.params.name || '';
    name = name.replace(/[^a-zA_Z]/, '');
    if (!name.length) {
        res.send({});
    } else {
        var query = client.query('SELECT * FROM BEATLES WHERE name =\''+name+'\' LIMIT 1');
        var data = {};
        query.on('row', function(row) {
            data = row;
            res.send(data);
        });
    };
});
app.listen(80, '127.0.0.1');

5
这段内容表达了对createServer方法的困惑,它让人误以为可以随意创建服务器,与WAMP模式不同,该模式在5年前只需在Windows XP笔记本电脑上安装(即'创建')一次服务器,之后就再也没有创建过。现在突然又可以随意创建服务器,这让人感到困惑。 - dsdsdsdsd
1
当我在 C:\Program Files\nodejs\ 中搜索名为 express 的文件或目录时,没有匹配项,那么 express 是什么?它从哪里来? - dsdsdsdsd
2
Express是一个中间件和框架的集合,它使在node.js中创建Web服务器变得更容易。您需要使用npm来安装它。您可以在此处找到更多信息:http://expressjs.com/ - Timothy Meade
这是非常好的解释。我有一个问题,是否需要在NodeJS和浏览器两个环境中使用动态路径? - M.Abulsoud

42

我注意到其他答案解释了require是什么以及在Node中用于加载模块,但没有完整说明如何在浏览器中工作时加载Node模块。

实现这个很简单。像你描述的那样使用npm安装你的模块,该模块本身将位于一个通常称为node_modules的文件夹中。

现在将其加载到你的应用程序中最简单的方法是使用一个指向此目录的脚本标签引用它。例如,如果你的node_modules目录与index.html位于同一级别的项目根目录中,则可以在index.html中写入以下内容:

<script src="node_modules/ng"></script>

整个脚本现在将加载到页面中 - 这样您就可以直接访问其变量和方法。

对于更大型的项目,还有其他更常用的方法,例如像require.js这样的模块加载器。在这两种方法中,我自己没有使用过Require,但我认为许多人认为这是最好的选择。


你只需进入项目文件夹的根目录,键入 npm install <模块名称>。例如,如果你键入 npm install bootstrap,它将把 Bootstrap 安装到名为 node_modules/bootstrap 的目录中。现在,你可以按上面的描述将 Bootstrap 加载到你的应用程序中了。显然,你需要安装 node 和 npm 才能使用它。如果你需要更多信息,请提供你得到的错误。 - Sam Redway
<模块名称>?这是我的目录结构。根文件夹是 xyzxyz/index.html 使用 script 标签指向 xyz/js/scripts.jsxyz/js/scripts.js 中有代码 require('./module1.js');require('./module2.js');module1.js/module2.js 也在 xyz/js 文件夹中。现在,我该如何使 scripts.js 在浏览器中可用? - overexchange
喜欢这个解释。只记得不是所有的 node_modules 都会被浏览器的 JS 引擎解析。 - user12582392

36

它用于加载模块。我们来看一个简单的例子。

在文件circle_object.js中:

var Circle = function (radius) {
    this.radius = radius
}
Circle.PI = 3.14

Circle.prototype = {
    area: function () {
        return Circle.PI * this.radius * this.radius;
    }
}

我们可以通过require来使用它,例如:

node> require('circle_object')
{}
node> Circle
{ [Function] PI: 3.14 }
node> var c = new Circle(3)
{ radius: 3 }
node> c.area()
require() 方法用于加载和缓存 JavaScript 模块。因此,如果您想要将本地的相对 JavaScript 模块加载到 Node.js 应用程序中,可以简单地使用 require() 方法。
示例:
var yourModule = require( "your_module_name" ); //.js file extension is optional

12
如果你想在网页上使用它,该怎么办? - neuromancer
2
我正在尝试在网页中加载上述内容! - neuromancer
7
第一个代码块是否应该放在名为circle_object.js的文件中? - user1416227

35

死灵法术。
在我看来,现有的答案还远远不够。

起初,它非常令人困惑。
你有一个(从未定义过的)函数 "require",用于获取模块。
而在这些(CommonJS)模块中,你可以使用 require、exports和module
而它们从未被定义过。
虽然在JS中使用未定义的变量并不新鲜,但你不能使用未定义的函数。
所以一开始看起来有点像魔法。
但所有的魔法都基于欺骗。

当你深入挖掘时,它实际上非常简单:
Require只是一个(非标准的)函数定义在全局范围
(或者更确切地说,在伪全局范围;浏览器中的全局范围=窗口对象,在NodeJS中的全局对象)。


请注意,默认情况下,“require函数”仅在NodeJS中实现,而不在浏览器中实现。
此外,请注意增加混淆的是,对于浏览器,有RequireJS,尽管名称包含字符“require”,但RequireJS绝对不实现require/CommonJS - 而是实现AMD,这是类似但不同的东西(也就是不兼容)。
这最后一点是你理解require的重要事情之一。
现在,作为这样的回答,“require是什么”,我们“简单地”需要知道这个函数做什么。
这可能最好通过代码来解释。

这里有一个由Michele Nasti提供的简单实现, 你可以在他的github页面上找到相关代码。

我们将我们的最小化"require"函数实现称为"myRequire":

function myRequire(name) 
{
    console.log(`Evaluating file ${name}`);
    if (!(name in myRequire.cache)) {
        console.log(`${name} is not in cache; reading from disk`);
        let code = fs.readFileSync(name, 'utf8');
        let module = { exports: {} };
        myRequire.cache[name] = module;
        let wrapper = Function("require, exports, module", code);
        wrapper(myRequire, module.exports, module);
    }
    console.log(`${name} is in cache. Returning it...`);
    return myRequire.cache[name].exports;
}
myRequire.cache = Object.create(null);
window.require = myRequire;
const stuff = window.require('./main.js');
console.log(stuff);

现在你注意到了,这里使用了对象“fs”。
为了简单起见,Michele只是导入了NodeJS的fs模块:

const fs = require('fs');

这并不是必需的。
因此,在浏览器中,您可以使用同步 XmlHttpRequest 简单实现 require:

const fs = {
    file: `
    // module.exports = \"Hello World\";
        
    module.exports = function(){ return 5*3;};
    
    `
    , getFile(fileName: string, encoding: string): string
    {
        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
        let client = new XMLHttpRequest();
        // client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");

        // open(method, url, async)
        client.open("GET", fileName, false);
        client.send();
        if (client.status === 200)
            return client.responseText;

        return null;
    }


    , readFileSync: function (fileName: string, encoding: string): string
    {
        // this.getFile(fileName, encoding);
        return this.file; // Example, getFile would fetch this file 
    }
};

基本上,所需的代码是这样的,它会下载一个JavaScript文件,将其在匿名命名空间(也称为函数)中进行eval操作,使用参数"require"、"exports"和"module",然后返回exports,即对象的公共函数和属性。

请注意,这个评估过程是递归的:你需要文件,这些文件可以再次需要其他文件。

这样一来,你模块中使用的所有“全局”变量都是require包装函数命名空间中的变量,不会污染全局范围中不需要的变量。

此外,这种方式使您能够在不依赖命名空间的情况下重用代码,从而在JavaScript中实现了“模块化”。“模块化”打了引号,因为这并不完全准确,因为您仍然可以编写window.bla/global.bla,从而仍然会污染全局范围...此外,这种方式还建立了私有和公共函数之间的分离,其中公共函数即为exports。

现在,不再需要说

module.exports = function(){ return 5*3;};

你也可以说:

function privateSomething()
{
    return 42:
}


function privateSomething2()
{
    return 21:
}


module.exports = {
      getRandomNumber: privateSomething
     ,getHalfRandomNumber: privateSomething2
};

并返回一个对象。

另外,由于您的模块在带有参数“require”、“exports”和“module”的函数中评估,因此您的模块可以使用未声明的变量“require”、“exports”和“module”,这可能会令人吃惊。那里的 require 参数当然是指保存在变量中的 require 函数的指针。
很酷,对吧?
从这个角度来看,require 失去了其魔力,变得简单。

现在,真正的 require 函数会做更多的检查和奇怪的事情,当然,但这就是它的实质。

另外,在2020年及以后,您应该使用ECMA实现而不是require:

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";

如果您需要动态的非静态导入(例如根据浏览器类型加载polyfill),则可以使用ECMA-import函数/关键字:

var promise = import("module-name");

请注意,import不像require一样同步。
相反,import是一个Promise。
var something = require("something");

成为

var something = await import("something");

因为导入返回一个承诺(异步)。

所以基本上,与 require 不同,import 用 fs.readFileAsync 替换了 fs.readFileSync。

async readFileAsync(fileName, encoding) 
{
    const textDecoder = new TextDecoder(encoding);
    // textDecoder.ignoreBOM = true;
    const response = await fetch(fileName);
    console.log(response.ok);
    console.log(response.status);
    console.log(response.statusText);
    // let json = await response.json();
    // let txt = await response.text();
    // let blo:Blob = response.blob();
    // let ab:ArrayBuffer = await response.arrayBuffer();
    // let fd = await response.formData()
    // Read file almost by line
    // https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#Example_2_-_handling_text_line_by_line
    let buffer = await response.arrayBuffer();
    let file = textDecoder.decode(buffer);
    return file;
} // End Function readFileAsync

当然,这需要导入函数也是异步的

"use strict";
async function myRequireAsync(name) {
    console.log(`Evaluating file ${name}`);
    if (!(name in myRequireAsync.cache)) {
        console.log(`${name} is not in cache; reading from disk`);
        let code = await fs.readFileAsync(name, 'utf8');
        let module = { exports: {} };
        myRequireAsync.cache[name] = module;
        let wrapper = Function("asyncRequire, exports, module", code);
        await wrapper(myRequireAsync, module.exports, module);
    }
    console.log(`${name} is in cache. Returning it...`);
    return myRequireAsync.cache[name].exports;
}
myRequireAsync.cache = Object.create(null);
window.asyncRequire = myRequireAsync;
async () => {
    const asyncStuff = await window.asyncRequire('./main.js');
    console.log(asyncStuff);
};

更好了,是吧?
嗯,除了没有ECMA的动态同步导入方式(没有promise),其他都很好。

现在,为了理解其影响,如果您不知道这是什么,您绝对可能想要在此阅读关于promises/async-await,

但简单来说,如果函数返回一个promise,它可以被“awaited”:

"use strict";
function sleep(interval) 
{
    return new Promise(
        function (resolve, reject) 
        {
            let wait = setTimeout(function () {
            clearTimeout(wait);
            //reject(new Error(`Promise timed out ! (timeout = ${timeout})`));
            resolve();
        }, interval);
    });
}

然后,Promise 通常会像这样使用:

function testSleep() 
{
    sleep(3000).then(function () 
    {
        console.log("Waited for 3 seconds");
    });
}

但是当你返回一个Promise时,你也可以使用await,这意味着我们摆脱了回调(有点 - 实际上,它被编译器/解释器中的状态机所取代)。 通过这种方式,我们使异步代码感觉像同步代码,因此现在我们可以使用try-catch来处理错误。 请注意,如果您想在函数中使用await,则该函数必须声明为async(因此是async-await)。
async function testSleep() 
{
    await sleep(5000);
    console.log("i waited 5 seconds");
}

请注意,在JavaScript中,无法从同步函数(您知道的那些函数)中阻塞地调用异步函数。因此,如果您想使用await(又名ECMA-import),则所有代码都需要是异步的,这很可能会成为一个问题,如果不是所有代码都已经是异步的话...
require的简化实现失败的一个例子是当您需要一个无效的JavaScript文件时,例如当您需要css、html、txt、svg和图像或其他二进制文件时。
很容易看出原因:
如果您将HTML放入JavaScript函数体中,您当然会得到...
SyntaxError: Unexpected token '<'

由于 Function("bla", "<doctype...")

现在,如果您想将其扩展到例如包括非模块,您可以仅检查下载的文件内容是否为code.indexOf("module.exports") == -1(或xml请求mime类型),然后添加jQuery作为脚本标记(eval不同)而不是Func(只要您在浏览器中就可以正常工作)。由于使用Fetch / XmlHttpRequests下载受同源策略限制,并且完整性由SSL / TLS确保,因此在这里使用eval相当无害,前提是在将它们添加到您的站点之前检查了JS文件,但这应该是标准操作程序。

请注意,有几种类似于require的功能实现:

  • CommonJS (CJS) 格式, 在 Node.js 中使用,采用 require 函数和 module.exports 定义依赖关系和模块。npm 生态系统是建立在这个格式之上的。(以上就是所实现的内容)

  • Asynchronous Module Definition (AMD) 格式, 用于浏览器中,采用 define 函数定义模块。(基本上,这是过时的复杂垃圾,你永远不想使用它)。此外,AMD 是由 RequireJS 实现的格式(请注意,尽管名称包含“require”字符,但 AMD 绝对不是 CommonJS)。

  • ES 模块(ESM)格式。自 ES6(ES2015)以来,JavaScript 支持本地模块格式。它使用 export 关键字导出模块的公共 API 和 import 关键字导入它。如果你不关心老旧浏览器,如 Safari 和 IE/EdgeHTML,那么这是你应该使用的格式

  • System.register 格式,设计用于支持 ES6 模块在 ES5 中使用。(如果你需要支持旧浏览器(Safari 和 IE 以及手机/平板电脑上的旧版本 Chrome),因为它可以加载所有格式(对于某些内容,需要插件),可以处理循环依赖,以及 CSS 和 HTML。不过,不要把你的模块定义为 system.register 格式——这个格式相当复杂,并且记住,它可以读取其他更简单的格式

  • Universal Module Definition (UMD) 格式,与上述所有格式(除 ECMA 外)兼容,在浏览器和 Node.js 中都可以使用。它特别适用于编写可在 NodeJS 和浏览器中使用的模块。它有一些缺陷,因为它不支持最新的 ECMA 模块,但是它可以使用 system.register 代替。

关于函数参数“exports”的重要说明:
JavaScript使用值共享调用,这意味着对象作为指针传递,但指针值本身是按值传递的,而不是按引用传递的。因此,您不能通过分配新对象来覆盖exports。相反,如果要覆盖exports,则需要将新对象分配给module.exports,因为嘿,module是按值传递的指针,但module.exports中的exports是对原始exports指针的引用。

关于模块范围的重要说明:
模块被评估一次,然后由require缓存
这意味着所有模块都具有单例范围。
如果您想要非单例范围,您必须执行类似以下操作:

var x = require("foo.js").createInstance();

或者简单地说

var x = require("foo.js")();

通过你的模块返回适当的代码。

如果你需要在浏览器中支持CommonJS(IE5+,Chrome,Firefox),
请查看我的代码 我在Michele Nasti的项目中的评论


1
哇,多么详尽的答案啊!自2012年以来,主流JavaScript世界发生了很多变化——因此,这个大局观非常受欢迎!一个问题/确认:CommonJS格式是否(必须)在运行时导入(而不是解析时间或构建时间)? ——在运行时导入是否会对其在某些情况下与ES2015模块的可行性产生影响(比如其在注入内容脚本中的使用)? - Josh Desmond
1
@Josh Desmond:我认为ES2015模块和require之间的主要区别在于,ES2015模块是“静态”导入,这意味着程序流可以更好地分析和优化,而require是“动态”导入,可能会被命中或不被命中,具体取决于if语句。无论哪种方式,CommonJS可能在运行时被导入,这意味着第一次运行特定文件中的特定函数后,所有内容都已被缓存并可以直接访问。在这方面,ECMA静态导入可能更灵活,这意味着它们可能更高效,但可能不是这样。 - Stefan Steiger
1
@Josh Desmond:无论如何,这只会在第一次执行时有所影响,而不是在后续的执行中,因此正确的方法可能是编写一个预热脚本,调用每个文件中的每个函数一次,以便任何后续的调用都将使用缓存对象执行,而不需要磁盘访问,也就是说,这是最快的方式。可能更重要的是您的机器有多少RAM,而不是您使用CommonJS还是ECMA-imports。 - Stefan Steiger

24

当您在浏览器中运行JavaScript时,您可以访问像“window”或Math这样的变量。您不需要声明这些变量,它们已经为您编写,您可以随时使用。

好了,当您在Node.js环境中运行文件时,有一个变量可供您使用。它被称为“module”,它是一个对象。它有一个名为“exports”的属性。它的工作方式如下:

在我们将命名为example.js的文件中,您编写:

example.js

module.exports = "some code";

现在,您想要在另一个文件中使用字符串 "some code"。

我们将命名另一个文件为 otherFile.js

在该文件中,您写入:

otherFile.js

let str = require('./example.js')

那个require()语句会读取你放在括号里的文件,并寻找保存在module.exports属性上的数据。你代码中的let str = ...表示require语句返回的内容被存储到了str变量中。

所以在这个例子中,其他文件otherFile.js现在有如下内容:

let string = "some code";

  • 或 -

let str = require('./example.js').module.exports

注意:

在require语句中写的文件名如果是本地文件,应该是指向example.js的文件路径。默认情况下,.js扩展名会被自动添加,所以我没必要写它。

当需要引入node.js库(比如Express)时,你可以使用类似的方式。在express.js文件中有一个名为"module"的对象,以及一个名为"exports"的属性。

因此,在幕后看起来大概是这样的(我对细节不太熟悉,但是这足以说明概念):

express.js

module.exports = function() {
    //It returns an object with all of the server methods
    return {
        listen: function(port){},
        get: function(route, function(req, res){}){}
     }
}
如果您需要引入一个模块的话,代码如下: const moduleName = require("module-name");
如果您需要引入一个本地文件的话,代码如下: const localFile = require("./path/to/local-file");
(请注意文件名开头的 ./ 符号)
此外,默认情况下,导出的是一个对象,例如 module.exports = {}。因此,在给 module.exports 赋值之前,您可以编写 module.exports.myfunction = () => {}。但您也可以通过编写 module.exports = "我不再是一个对象了" 来替换该对象。

WordPress本身不支持require()函数。 - azuldev

10

module.exports和require有两种不同的用法:

(详见此处)

用法1:
导出文件 (misc.js):

var x = 5;
var addX = function(value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;

其他文件:

var misc = require('./misc');
console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(10));

口味 2
导出文件(user.js):

var User = function(name, email) {
  this.name = name;
  this.email = email;
};
module.exports = User;

其他文件:

var user = require('./user');
var u = new user();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接