构建node.js中需要的库的最佳实践

构建node.js中需要的库的最佳实践,node.js,design-patterns,require,Node.js,Design Patterns,Require,我有几个包含帮助函数的实用程序库,我想加载它们,以便从控制器使用它们,我想知道 在node中编码实用程序库的最佳实践是什么 我有点困惑,因为有几种方法可以做到这一点,我不确定什么是最好的/更合适的/更可靠的。这里有两个选项,但我想知道它们是否是最好的(例如,我见过使用module.exports=exports=function(){},等等的代码段) //选项1.js //选项2.js "use strict"; module.exports = { test1 : func

我有几个包含帮助函数的实用程序库,我想加载它们,以便从控制器使用它们,我想知道 在node中编码实用程序库的最佳实践是什么

我有点困惑,因为有几种方法可以做到这一点,我不确定什么是最好的/更合适的/更可靠的。这里有两个选项,但我想知道它们是否是最好的(例如,我见过使用
module.exports=exports=function(){}
,等等的代码段)

//选项1.js


//选项2.js

"use strict";

module.exports =  {

     test1 : function(){ console.log('soy test1')},
     test2 :  function(){ console.log('soy test2')}

};
//test_controller.js

/* Requiring helpers in different ways */
var option1 = require('./option1.js')();
var option2 = require('./option2.js');

对于无状态实用程序库,option2.js是一种选择,因为不需要
模块中的代码。每次
require
时都会导出要执行的
,这就是调用
require('./option1.js')()
使用option1.js时发生的情况

另一方面,如果您的模块公开了创建保持状态的对象的构造函数,那么您需要option1.js。比如说,

person.js:

module.exports = function(firstName,lastName){
    this.firstName = firstName;
    this.lastName = lastName;
};
然后使用它:

var Person = require("./person");

var person1 = new Person("Foo","Bar");
var person2 = new Person("Joe","Shmoe");

option1.js(如上所示)的另一个优点是,它允许您将参数传递到模块中。

我认为我的文件分为三个部分:

第1节:CommonJS依赖项 您不需要任何额外的包装函数。所有节点模块都由node.js在一个函数中创建,这样做没有任何好处,只会增加混乱

第2节:普通JavaScript代码 如果需要的话,这应该是带有少量支持变量或顶级模块代码的函数

var MY_CONST = 42;

function helper1() {
    //excellent code here
}

function helper2() {
    //excellent code here
}
保持第2节纯JS。不要在中间的“纯”部分使用commonJS习惯用法。不要使用
模块
导出
要求
,等等。这只是我个人的指导原则,因为JS本身是稳定的,但打包到模块中仍然需要很多更改,最好将无关的、可能更改的公共JS位与感兴趣的代码位分开。ECMAScript 6模块最有可能在几年内取代CommonJS,因此,保持第2节为纯ECMAScript 5并制作一个“CommonJS三明治”,让您自己更容易做到这一点™" 我喜欢这样称呼它

第3节:公共出口
  • 将所有导出放在末尾还可以让您快速了解公共API是什么,并防止由于不小心的复制/粘贴而意外导出属性
  • 我更喜欢上面的
    exports.foo=foo;
    语法,而不是将
    module.exports
    分配给一个新的对象文字。我发现这避免了对象文字的最后一个属性的尾部逗号问题
  • 用你的
    require
    exports
    语句做任何其他事情几乎肯定是不必要的,也是不必要的花哨或魔术。在你获得进步之前,不要在这里做任何花哨的事情。(即使如此,如果你不是TJ Holowaychuk,你可能只是在做傻事)
我应该出口什么 单个函数(@substack样式) 保持小而简单

功能对象 如果模块是一组辅助函数,则应将包含这些函数的对象导出为属性

var foo = require("foo");

function doubleFoo(value) {
  return foo(value) * 2;
}

function tripleFoo(value) {
  return foo(value) * 3;
}

exports.doubleFoo = doubleFoo;
exports.tripleFoo = tripleFoo;
构造函数 如果您的模块是面向对象的类设计,请导出构造函数

function GoCart() {
  this.wheels = 4;
}

GoCart.prototype.drive = function drive() {
  //vroom vroom
}

module.exports = GoCart;
工厂/配置关闭函数 一旦你掌握了以上两种模式(真的!),并且自信地导出一个包含选项的工厂函数,也许还可以做一些其他动态的事情,那么就去做吧,但如果有疑问,就坚持前两种更简单的选择

//do-stuff.js
function doStuff(howFast, what) {
   return "I am doing " + what + " at speed " + howFast;
}

function setup(options) {
  //The object returned by this will have closure access to options
  //for its entire lifetime
  return {doStuff: doStuff.bind(null, options.howFast)};
}

module.exports = setup;
所以你可以像这样使用它

var doStuff = require("./do-stuff")({howFast: "blazing speed"});
console.log(doStuff.doStuff("jogging"));
//"I am doing jogging at speed blazing speed"

谢谢@go oleg。关于用例和性能的非常有趣的评论:)非常好的回答@Peter。对模块设计非常有用。我会记住你的建议。请你提供关于“导出一个工厂函数,该函数包含选项,可能做一些其他动态的事情”的示例/链接“。我对在node.js代码中应用更多的架构技术感兴趣。这个答案已经过时了,因为它没有解决高级的新导出/导入语法。这仍然是很好的信息,但它是不完整的,而且新语法有性能优势(也可以说是可读性的改进)。呃,从NodeV6开始,导出/导入语法仍然不受支持。这里我们讨论的是非transpiled node.js,而不是一般意义上的ES2015。您对导出模块的看法如何。导出=(a,b)=>{return a+b}意味着箭头函数我将避免这种情况。我喜欢将commonjs语法与实际的实现代码分开。同样命名的函数有助于更好地进行堆栈跟踪,因此命名它们有助于调试。请注意,接受的答案和这个问题都非常古老,JS已经更新了导入/导出语句,这些语句可以提高性能和可读性,但在撰写本文时,当前已被接受的答案中并未涉及这些语句。@KyleBaker您能提供一个例子吗?我现在没有时间写出符合我标准的答案。然而,MDN有一些例子。目前可在此处进行深入勘探:
var foo = require("foo");

function doubleFoo(value) {
  return foo(value) * 2;
}

function tripleFoo(value) {
  return foo(value) * 3;
}

exports.doubleFoo = doubleFoo;
exports.tripleFoo = tripleFoo;
function GoCart() {
  this.wheels = 4;
}

GoCart.prototype.drive = function drive() {
  //vroom vroom
}

module.exports = GoCart;
//do-stuff.js
function doStuff(howFast, what) {
   return "I am doing " + what + " at speed " + howFast;
}

function setup(options) {
  //The object returned by this will have closure access to options
  //for its entire lifetime
  return {doStuff: doStuff.bind(null, options.howFast)};
}

module.exports = setup;
var doStuff = require("./do-stuff")({howFast: "blazing speed"});
console.log(doStuff.doStuff("jogging"));
//"I am doing jogging at speed blazing speed"