Node.js module.exports的目的是什么,你如何使用它?

mrw*_*ter 1397 javascript node.js

Node.js module.exports的目的是什么,你如何使用它?

我似乎无法找到任何关于此的信息,但它似乎是Node.js的一个相当重要的部分,因为我经常在源代码中看到它.

根据Node.js文档:

对当前的参考 module.特别module.exports 是与exports对象相同.有关src/node.js更多信息,请参阅

但这并没有真正帮助.

究竟module.exports做了什么,一个简单的例子是什么?

Aln*_*tak 1566

module.exports是作为require调用结果实际返回的对象.

exports变量最初设置为同一个对象(即它是一个简写的"别名"),因此在模块代码中,您通常会编写如下内容:

let myFunc1 = function() { ... };
let myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;
Run Code Online (Sandbox Code Playgroud)

导出(或"公开")内部作用域函数myFunc1myFunc2.

在调用代码中,您将使用:

const m = require('./mymodule');
m.myFunc1();
Run Code Online (Sandbox Code Playgroud)

最后一行显示结果require(通常)只是一个可以访问其属性的普通对象.

注意:如果你覆盖,exports那么它将不再引用module.exports.因此,如果您希望为此分配新对象(或函数引用),exports则还应将该新对象分配给module.exports


值得注意的是,添加到exports对象的名称不必与您要添加的值的模块内部作用域名称相同,因此您可以:

let myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required
Run Code Online (Sandbox Code Playgroud)

其次是:

const m = require('./mymodule');
m.shortName(); // invokes module.myVeryLongInternalName
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案 - 在我看来,'暴露'将是比'出口'更好的术语选择 (115认同)
  • 模块要求应为**var m = require('./ mymodule');**,带点和斜线.这样Node.js知道我们正在使用本地模块. (73认同)
  • 一定要使用:require('./ module_name')语法,因为可能有一些其他node.js模块带有一些名称,而不是选择你自己的模块,它将选择与node.js一起安装的模块. (7认同)
  • 啊,我好像找到了它...... http://www.commonjs.org/specs/modules/1.0/ (5认同)
  • @UpTheCreek有一个悠久的传统,即将模块公开的公共符号称为"导出",这可以追溯到许多编程系统和数十年.这不是Node开发人员发明的新术语. (3认同)
  • @ ApopheniaOverload - 您可以执行"exports.func1,exports.func2等"以从一个文件中获取多个公开的方法. (2认同)
  • @reviewers - 这个答案有超过 1000 个赞成票。请*非常仔细地*检查编辑内容。我刚刚恢复了今天早些时候所做的不必要的事情。 (2认同)

Jed*_*son 213

这已经得到了回答,但我想补充一些说明......

你可以使用它们exports并将module.exports代码导入你的应用程序,如下所示:

var mycode = require('./path/to/mycode');

您将看到的基本用例(例如,在ExpressJS示例代码中)是您exports在.js文件中设置对象的属性,然后使用该文件导入require()

因此,在一个简单的计数示例中,您可以:

(counter.js):

var count = 1;

exports.increment = function() {
    count++;
};

exports.getCount = function() {
    return count;
};
Run Code Online (Sandbox Code Playgroud)

...然后在您的应用程序(web.js,或任何其他.js文件):

var counting = require('./counter.js');

console.log(counting.getCount()); // 1
counting.increment();
console.log(counting.getCount()); // 2
Run Code Online (Sandbox Code Playgroud)

简单来说,您可以将所需文件视为返回单个对象的函数,并且可以将属性(字符串,数字,数组,函数,任何内容)添加到通过设置它们返回的对象exports.

有时您会希望从require()调用返回的对象是您可以调用的函数,而不仅仅是具有属性的对象.在这种情况下,您还需要设置module.exports,如下所示:

(sayhello.js):

module.exports = exports = function() {
    console.log("Hello World!");
};
Run Code Online (Sandbox Code Playgroud)

(app.js):

var sayHello = require('./sayhello.js');
sayHello(); // "Hello World!"
Run Code Online (Sandbox Code Playgroud)

export和module.exports之间的区别在这里的答案中有更好的解释.


Ale*_*aut 60

请注意,NodeJS模块机制基于CommonJS模块,这些模块在许多其他实现(如RequireJS)中受支持,但也包括SproutCore,CouchDB,Wakanda,OrientDB,ArangoDB,RingoJS,TeaJS,SilkJS,curl.js,甚至Adobe Photoshop(通过PSLib)).您可以在此处找到已知实施的完整列表.

除非您的模块使用特定于节点的功能或模块,否则我强烈建议您使用exports而不是使用module.exports CommonJS标准,而不是其他实现不支持.

NodeJS的另一个特定功能是,当您为新对象分配引用时,exports而不是像在Jed Watson在此线程中提供的最后一个示例中那样仅向其添加属性和方法.我个人不鼓励这种做法,因为这打破了CommonJS模块机制的循环引用支持.然后,所有实现都不支持它,Jed示例应该以这种方式(或类似的)编写,以提供更通用的模块:

(sayhello.js):

exports.run = function() {
    console.log("Hello World!");
}
Run Code Online (Sandbox Code Playgroud)

(app.js):

var sayHello = require('./sayhello');
sayHello.run(); // "Hello World!"
Run Code Online (Sandbox Code Playgroud)

或者使用ES6功能

(sayhello.js):

Object.assign(exports, {
    // Put all your public API here
    sayhello() {
        console.log("Hello World!");
    }
});
Run Code Online (Sandbox Code Playgroud)

(app.js):

const { sayHello } = require('./sayhello');
sayHello(); // "Hello World!"
Run Code Online (Sandbox Code Playgroud)

PS:看起来Appcelerator还实现了CommonJS模块,但没有循环引用支持(参见:Appcelerator和CommonJS模块(缓存和循环引用))


Ale*_*aut 34

如果将新对象的引用分配给exports和/或,则必须注意以下几点modules.exports:

1.预先附于原始的所有属性/方法exportsmodule.exports当然是丢失,因为导出对象现在将引用另一个新的一个

这很明显,但是如果在现有模块的开头添加导出的方法,请确保本机导出的对象最后没有引用另一个对象

exports.method1 = function () {}; // exposed to the original exported object
exports.method2 = function () {}; // exposed to the original exported object

module.exports.method3 = function () {}; // exposed with method1 & method2

var otherAPI = {
    // some properties and/or methods
}

exports = otherAPI; // replace the original API (works also with module.exports)
Run Code Online (Sandbox Code Playgroud)

2.在其中一个exportsmodule.exports引用新值的情况下,它们不再引用同一个对象

exports = function AConstructor() {}; // override the original exported object
exports.method2 = function () {}; // exposed to the new exported object

// method added to the original exports object which not exposed any more
module.exports.method3 = function () {}; 
Run Code Online (Sandbox Code Playgroud)

3.棘手的后果.如果更改,参照上述两个exportsmodule.exports,很难说哪个API暴露(它看起来像module.exports胜)

// override the original exported object
module.exports = function AConstructor() {};

// try to override the original exported object
// but module.exports will be exposed instead
exports = function AnotherConstructor() {}; 
Run Code Online (Sandbox Code Playgroud)


ani*_*ish 29

module.exports属性或exports对象允许模块选择应与应用程序共享的内容

在此输入图像描述

我在这里有关于module_export的视频


psp*_*spi 18

将程序代码划分为多个文件时,module.exports用于将变量和函数发布给模块的使用者.require()源文件中的调用将替换为module.exports从模块加载的相应内容.

编写模块时请记住

  • 模块加载被缓存,只有初始调用评估JavaScript.
  • 可以在模块中使用局部变量和函数,而不是所有东西都需要导出.
  • module.exports对象也可以作为exports速记.但是当返回单一功能时,请始终使用module.exports.

模块导出图

根据:"模块第2部分 - 编写模块".


qia*_*hao 9

引用链接是这样的:

exports = module.exports = function(){
    //....
}
Run Code Online (Sandbox Code Playgroud)

exports或者module.exports,例如函数或变量的属性将暴露在外面

有些事情你必须更加注意:不要override出口.

为什么?

因为只导出module.exports的引用,所以可以将属性添加到导出中,但是如果覆盖导出,则引用链接将被破坏.

好例子 :

exports.name = 'william';

exports.getName = function(){
   console.log(this.name);
}
Run Code Online (Sandbox Code Playgroud)

坏例子:

exports = 'william';

exports = function(){
     //...
}
Run Code Online (Sandbox Code Playgroud)

如果您只想暴露一个函数或变量,如下所示:

// test.js
var name = 'william';

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

// index.js
var test = require('./test');
test();
Run Code Online (Sandbox Code Playgroud)

这个模块只暴露了一个函数,name的属性对于外部是私有的.


Jum*_*Man 6

当您下载并安装node.js(如http,sys等)时,node.js中有一些默认或现有模块.

由于它们已经在node.js中,当我们想要使用这些模块时,我们基本上就像导入模块一样,但为什么呢?因为它们已经存在于node.js. 导入就像从node.js中取出它们并将它们放入程序中.然后使用它们.

导出正好相反,你创建了你想要的模块,让我们说模块addition.js并将该模块放入node.js,你可以通过导出它来实现.

之前,我在这里写东西,记住,module.exports.additionTwo是一样exports.additionTwo

嗯,这就是我们喜欢的原因

exports.additionTwo = function(x)
{return x+2;};
Run Code Online (Sandbox Code Playgroud)

小心路径

假设您已经创建了一个addition.js模块,

exports.additionTwo = function(x){
return x + 2;
};
Run Code Online (Sandbox Code Playgroud)

在NODE.JS命令提示符上运行此命令时:

node
var run = require('addition.js');
Run Code Online (Sandbox Code Playgroud)

这将错误说出来

错误:找不到模块addition.js

这是因为node.js进程无法使用addition.js,因为我们没有提到路径.因此,我们可以使用NODE_PATH设置路径

set NODE_PATH = path/to/your/additon.js
Run Code Online (Sandbox Code Playgroud)

现在,这应该成功运行没有任何错误!

还有一件事,您还可以通过不设置NODE_PATH来运行addition.js文件,返回到nodejs命令提示符:

node
var run = require('./addition.js');
Run Code Online (Sandbox Code Playgroud)

由于我们通过说它在当前目录中提供路径,因此它./也应该成功运行.


Sha*_*ane 5

模块将相关代码封装到单个代码单元中。创建模块时,这可以解释为将所有相关函数移至文件中。

假设有一个文件Hello.js,其中包含两个函数

sayHelloInEnglish = function() {
  return "Hello";
};
sayHelloInSpanish = function() {
  return "Hola";
};
Run Code Online (Sandbox Code Playgroud)

仅当代码的效用超过一次调用时,我们才编写函数。

假设我们想要将函数的实用性增加到不同的文件(例如 World.js),在这种情况下导出一个文件就可以通过 module.exports 获得。

您可以通过下面给出的代码导出这两个函数

var anyVariable={
 sayHelloInEnglish = function() {
      return "Hello";
    };
  sayHelloInSpanish = function() {
      return "Hola";
    }; 
}
module.export=anyVariable;
Run Code Online (Sandbox Code Playgroud)

现在您只需要在 World.js 中输入文件名即可使用这些功能

var world= require("./hello.js");
Run Code Online (Sandbox Code Playgroud)