Node.js模块范式的基础?

我正在努力掌握一些基本的基本知识,而且我觉得这不仅阻碍了我,还导致了糟糕的代码,我不喜欢这样做。

我理解将代码的function块分解成单独模块的概念,比如说路由,数据库模型等,但是我真的很难理解如何正确编排所有这些独立模块的相互依赖的function。

让我举个例子说明我的斗争在哪里。

例1

我的ExpressJS“应用程序”安装在我的主程序模块中,就像您在每个教程中看到的一样。 不过,我也需要访问其他模块中的应用程序实例。 我怎么做? 我从各种教程中学到的一个方法是让整个模块导出一个函数,将应用程序作为参数,然后在函数中做我所需要的。 但是,在我看来,增加了很多事情的复杂性。 现在,我不但已经将一个完整的模块包含在一个函数中,而且似乎也失去了将多个函数,对象或其他variables导出该模块的能力。

模块作为一个function

module.exports = function(app) { blah; }; 

没有function的模块

 exports.func1 = function() { } exports.func2 = function() { } 

后者给了我更多的灵活性,但是我似乎被迫经常使用前者,因为我需要从其他地方传入类似于应用程序的东西。

例2

我正在使用连接rest为我的REST API。 我的API的所有代码都存放在一个名为“api”的单独模块中。 直到最近一直很好。 现在我需要从我的路由模块中访问api模块中的函数。 目前我的主要路线是我的api 之前定义的,所以我不能准确地将我的api导出传递到我的路由函数中。 我可能会扭转它们,但这只是掩盖了一个更大的问题。

总而言之,这个问题是相互依赖性日益增加的问题

随着我的代码库的增长,我发现越来越频繁的是,各个模块需要彼此协作 – 让它们全部完全无法实现是不可行的。 有时候这是可能的,但它是不洁的。

我觉得我错过了一些基本的Node.JS(或者也许只是Javascript)范例,用于pipe理所有这些。

如果有人能帮助我理解,我会最感激的。 我是其他语言(如C ++和Python)的经验丰富的开发人员,如果它有助于其他方面的东西。

试图总结这个问题

我觉得我没有充分传达我的发帖意图,所以让我试着总结一个有问题的问题。

server.js

 var http = require('http'), express = require('express'), app = express(); // Bunch of stuff done with app to get it set up var routes = require('routes.js')(app); 

app.js

 module.exports = function(app, express) { var router = express.router(); // code for routes app.use('/', router); } 

在上面的例子中,路由被分解到他们自己的模块中,但是该模块需要app和从server.js express对象才能起作用。 所以,按照我目前的理解,将这些路由到routes.js中的唯一方法是使routes.js导出一个大函数,然后使用这两个对象调用它们。

但是,如果我想要routes.js导出可能在其他地方使用的多个函数呢? 据我了解,我现在不能。 如果我想要做:

authentication.js

 var routes = require('routes'); // setup auth routes.doSomethingFunction(auth); 

我不能这样做,因为路由只是导出一个巨型函数。

每个节点模块只是一个对象。 该对象可用于外界的部分是module.exports对象,其中包含可以是函数或数据的属性。

require("xxx")命令为您获取该模块的exports对象(从中央caching或从尚未加载的.js文件中加载它)。

所以,代码共享很简单。 只要让每个模块在要共享代码的任何其他模块上执行require() ,并让这些模块确保可以通过它自己的exports对象访问共享函数。 这允许每个模块基本上是独立的。 它加载了所需的任何其他代码,并使重用代码变得更容易。 模块被caching,所以在许多其他模块的同一模块上执行大量require()操作只不过是caching查找而已,并不值得担心。

数据共享(如您的app对象)可以通过几种不同的方式来完成。 最常见的方法是当您加载模块时,只需调用模块的某种初始化函数,并将它可能需要的任何数据传递给它。 这将是推动模式。 或者,您也可以在某个模块中为某些数据请求另一个模块来执行拉模式。

所有这一切都是正确的代码组织更容易。 如果你开始觉得自己有意大利面或者相互依赖,那么也许你没有正确的代码组织,或者只是使用require()来引入给定模块所需的所有东西,你就有点太害羞了。 记住每个模块都会加载它自己需要的东西,所以你只需要担心你需要什么。 加载这些模块,他们将加载他们需要的东西。

你可能也想用对象来思考更多的东西,所以你把大多数属性放在某种对象上,而不是大量的松散的,单独共享的variables。 然后,您可以共享一个对象,并自动将该variables的所有属性提供给任何您共享的对象。


至于你与另一个模块共享app对象的问题,你可以这样做:

 // in your app module var express = require('express'); var app = express(); var otherModule = require('otherModule'); otherModule.setApp(app); // now otherModule has the singleton `app` object that it can use // in this case, otherModule must be initialized this way before it can do its job 

在这个例子中,我只使用了一个方法.setApp()来设置应用程序对象。 这意味着所有其他方法都可用于其他访问该模块。


这也可以用类似于构造函数的方法来完成:

 // in your app module var express = require('express'); var app = express(); var otherModule = require('otherModule')(app); 

这也有效,因为如果你想要的话,构造函数可以用其他方法返回一个对象。 如果你想能够从其他模块访问其他模块,但显然你只想要初始化一次,而不是在其他地方,那么你可以这样做:

 var otherModule = require('otherModule')(); 

从那些其他模块,并有构造函数只是检查,如果没有传递给它,那么它没有得到这个构造函数调用的app对象,所以它应该只是返回一个对象与其他方法。 或者,您可以使用上面的第一个代码块返回最初的require()所有方法。 你完全可以自由决定从require()返回什么。 它可以只是一个类似于构造函数的函数,它在被调用时会返回另一个对象。 它可以只是一个拥有方法的对象,或者(因为函数是也可以有属性的对象),你甚至可以返回一个类似于构造函数的函数,它也有方法(尽pipe这是一种不那么标准的方法事情)。

而且,您的构造函数可以根据传递给它的内容决定做什么,根据传递给它的不同行为给予它许多不同的行为。