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

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

我有点困惑,因为有几种方法来做到这一点,我不知道什么是最好/更合适/更可靠。 这里有2个选项,但我想知道,如果他们是最好的(例如,我已经看到使用module.exports = exports = function(){}等片段)

//option1.js


 "use strict"; module.exports = function(){ exports.test1 = function(){ console.log('hi I'm test1')}; exports.test2 = function(){ console.log('hi I'm test2')}; return exports; }; 

//option2.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'); 

我想我的文件在三个部分:

第1节:CommonJS依赖

 var lib1 = require("lib1"); var lib2 = require("lib2"); 

你不需要任何额外的包装函数。 所有的节点模块都被node.js 自动包装在一个函数中,这样做没有任何好处,只是增加了混乱

第2节:普通的JavaScript代码

如果需要的话,这应该几乎完全是function齐备的支持variables或顶级模块代码。

 var MY_CONST = 42; function helper1() { //excellent code here } function helper2() { //excellent code here } 

保留第2节纯JS。 在这个中间的“纯”部分不要使用commonJS成语。 不要使用moduleexportsrequire等等。这只是我个人的指导方针,因为JS本身是稳定的,但是对模块的封装仍然有很大的改变,最好保持CommonJS位是无关紧要的,并且可能会改变与有趣的代码分离。 ECMAScript 6模块最有可能在几年内取代CommonJS,因此,通过保留第2节纯ECMAScript 5并制作一个“CommonJS Sandwich™”,就像我喜欢的那样,让自己更容易。

第3节:CommonJS出口

 exports.helper1 = helper1; exports.helper2 = helper2; 
  • 把所有的出口放在最后也可以让你快速了解你的公共API是什么,并防止由于不小心的复制/粘贴而意外导出属性。
  • 我更喜欢上面的exports.foo = foo; 语法,而不是将module.exports分配给新的对象文字。 我发现这避免了与对象文字的最后一个属性的尾随逗号问题。
  • 做你requireexports陈述的任何事情几乎肯定是不必要的,不必要的光滑或魔术。 直到你被推进,在这里不要做任何事情。 (即使如此,如果你不是TJ Holowaychuk,你可能只是愚蠢的)

我应该输出什么

单个函数(@substack样式)

 function degreesToRadians(degrees) {} module.exports = degreesToRadians; 

保持小而简单。

function的一个对象

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

 var foo = require("foo"); function doubleFoo(value) { return foo(value) * 2; } function tripleFoo(value) { return foo(value) * 3; } exports.doubleFoo = doubleFoo; exports.tripleFoo = tripleFoo; 

一个构造函数

如果您的模块是面向对象使用的类devise,则导出构造函数

 function GoCart() { this.wheels = 4; } GoCart.prototype.drive = function drive() { //vroom vroom } module.exports = GoCart; 

工厂/configurationclosuresfunction

一旦你掌握了上述2种模式(真的!),并且感到有信心导出一个需要select的工厂函数,也许还有其他一些dynamic的东西,那就去做吧,但是如果有疑问的话,坚持前两个更简单的select。

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

对于无状态的实用程序库, option2.js是要走的路,因为不需要每次requirerequire执行module.exports的代码,这是在调用require('./option1.js')()时会发生的情况require('./option1.js')()使用option1.js

另一方面,如果你的模块暴露了创build保持状态的对象的构造函数,那么你会想要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的另一个优点是(如上所示),它可以让你传递参数到模块中。