我正努力在这里真正掌握一些基本的基础知识,我觉得它不仅阻碍了我,而且导致了糟糕的代码而且我不喜欢它。
我理解将代码的功能块分解为单独的模块的概念,比如说路由,数据库模型等,但是我真的很难理解如何正确地协调所有这些单独模块的相互依赖的功能。
让我举一个例子,说明我的斗争在哪里。
我的ExpressJS'应用'是在我的主程序模块中设置的,就像你在每个教程中看到的一样。但是我也需要访问其他模块中的app实例。我怎么做?我从各种教程中学到的一种方法是使整个模块导出一个函数,该函数将应用程序作为参数,然后在函数中执行我需要的操作。但在我看来,这给事情增添了很多复杂性。我现在不仅将一个整个模块包含在一个函数中,而且似乎无法从该模块中实际导出多个函数,对象或其他变量。
模块作为一种功能
module.exports = function(app) {
blah;
};
没有功能的模块
exports.func1 = function() {
}
exports.func2 = function() {
}
后者让我的眼睛更加灵活,但我似乎经常被迫使用前者,因为我需要从其他地方传递应用程序等内容。
我正在使用connect-rest作为我的REST API。我的API的所有代码都位于一个名为'api'的独立模块中。这一直很好,直到最近。现在我需要从我的路由模块内部访问api模块中的一个函数。目前我的主路由在我的api之前定义了,所以我无法将我的api导出完全传递给我的路由功能。我可能会反转它们,但这只是掩盖了一个更大的问题。
随着我的代码库的增长,我越来越频繁地发现各种模块需要相互协作 - 让它们完全保持海水状态是不可行的。有时它是可能的,但它是不洁净的。
我觉得我缺少一些基本的Node.JS(或者只是Javascript)范例,用于管理所有这些。
如果有人能帮助我理解我会非常感激。我是一个经验丰富的开发人员,使用其他语言,如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);
}
在上面的示例中,路由被拆分为自己的模块,但该模块需要来自server.js的app
和express
个对象才能运行。因此,根据我目前的理解,将这些转移到routes.js的唯一方法是使routes.js导出一个大函数,然后用你需要的两个对象调用它。
但是,如果我希望routes.js导出可能在其他地方使用的多个函数,该怎么办?根据我的理解,我现在不能。如果我想做什么怎么办:
authentication.js
var routes = require('routes');
// setup auth
routes.doSomethingFunction(auth);
我无法做到这一点,因为路由只导出一个大型功能。
答案 0 :(得分:2)
每个节点模块只是一个对象。外部世界可用的对象部分是module.exports
对象,它包含可以是函数或数据的属性。
require("xxx")
命令可以获取该模块的exports
对象(来自中央缓存,或者从.js文件加载它尚未加载)。
因此,代码共享很简单。让每个模块在它想要共享代码的任何其他模块上执行require()
,并让这些模块确保共享函数可以通过它自己的exports
对象访问。这允许每个模块基本上是独立的。它加载了所需的任何其他代码,使重用代码变得更加容易。模块被缓存,因此在许多其他模块的同一模块上执行大量require()
操作只不过是缓存查找而且不用担心。
数据共享(例如您的app
对象)可以通过几种不同的方式完成。最常见的方法是加载模块时只需为模块调用某种初始化函数,并将其传递给它可能需要的任何数据。这将是推模型。或者,您也可以执行拉模型,其中模块会向另一个模块询问某些数据。
使用正确的代码组织,所有这些都变得容易多了。如果你开始觉得你有意大利面或相互依赖,那么也许你没有合适的代码组织,或者你只是有点太害羞而只是使用require()
来提取给定模块所需的一切。请记住,每个模块都会加载它自己需要的任何东西,所以你只需要担心你需要什么。加载这些模块,他们将加载他们需要的东西。
您可能还想在对象方面考虑更多,因此您将大多数属性放在某种对象上,而不是大量松散的,单独共享的变量。然后,您可以共享一个对象,它会自动将该变量的所有属性提供给您与之共享的任何人。
关于与另一个模块共享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()
来设置app对象。这意味着所有其他方法都可用于对该模块的其他访问。
这也可以使用类似构造函数的方法完成:
// in your app module
var express = require('express');
var app = express();
var otherModule = require('otherModule')(app);
这也可以,因为构造函数可以根据需要返回一个带有其他方法的对象。如果您希望能够从其他模块中访问otherModule
,但显然您只想将其初始化一次,而不是在其他地方,那么您可以这样做:
var otherModule = require('otherModule')();
从那些其他模块并让构造函数检查如果没有传递给它,那么它没有从这个构造函数调用中获取app
对象,所以它应该只返回一个带有其他方法的对象。或者,您可以使用上面的第一个代码块返回初始require()
中的所有方法。您完全可以自由决定从require()
返回什么。它可以只是一个类似构造函数的函数,然后在调用它时返回另一个对象。它可以只是一个对象上有方法或(因为函数是也可以有属性的对象),你甚至可以返回一个类似构造函数的函数,它也有方法(尽管这是一种不那么标准的做法)事情)。
并且,你的构造函数可以根据传递给它的内容决定做什么,根据你传递给它的内容给出了很多不同的行为。