如何在node.js的多个文件中分割类定义?
我的Foo
类定义已经发展到我想要将其分割成多个文件的地步。 例如,我想要这样的东西:
// file foo.js 'use strict'; function Foo() { }; Foo.prototype.constructor = Foo; Foo.prototype.methodA = function() { console.log('methodA'); }; module.exports = Foo; // file foo-aux.js 'use strict'; Foo.prototype.methodB = function() { console.log('methodB'); this.methodA(); }; // file main.js 'use strict'; const Foo = require('./foo'); var foo = new Foo(); foo.methodB();
module.export
和require()
使上面的代码工作正确的组合是什么?
更新了答案
(完整的道具为McMath的详细答案 – 它比下面的原始答案更好地缩放,并提供了更好的代码重用的机会,并促使我更新这个答案,但是如果你不需要那里的全部混合路线,这是一个干净而简单的方法。)
修改Shaun Xubuild议的技巧 ,可以将主类定义作为parameter passing,以便require
在分离出的文件中接收该类定义。
创build一个带有index.js
的子目录来保存类定义和子文件是一个很好的做法 – 这就清楚地表明子文件是Foo
类的一部分:
main.js foo/ index.js foo-a.js foo-b.js
具体如下:
// foo/index.js 'use strict'; function Foo() {}; Foo.prototype.constructor = Foo; require('./foo-a')(Foo); require('./foo-b')(Foo); module.exports = Foo; // foo/foo-a.js 'use strict'; module.exports = function(Foo) { Foo.prototype.methodA = function() { console.log('methodA'); }; // more methods as desired... }; // foo/foo-b.js 'use strict'; module.exports = function(Foo) { Foo.prototype.methodB = function() { console.log('methodB'); this.methodA(); }; // more methods as desired... };
并称之为:
// main.js 'use strict'; const Foo = require('./foo/'); var foo = new Foo(); foo.methodB();
原来的答案
// file foo.js 'use strict'; function Foo() { }; Foo.prototype.constructor = Foo; Foo.prototype.methodA = function() { console.log('methodA'); }; require('./foo-aux')(Foo); // <== add this line module.exports = Foo; // file foo-aux.js 'use strict'; module.exports = function(Foo) { // <== wrap function definitions Foo.prototype.methodB = function() { console.log('methodB'); this.methodA(); }; }; // file main.js 'use strict'; const Foo = require('./foo'); var foo = new Foo(); foo.methodB(); // test $ node foo.js methodB methodA
我会考虑两种解决scheme,具体取决于我是否想要为每个文件定义一个方法,或者将多个相关方法分组到一个文件中。
每个文件一个方法
从这样的目录结构开始:
foo/ foo.a.js foo.b.js index.js main.js
Foo
一个方法可能是这样的:
// foo/foo.a.js module.exports = function() { console.log('Method A'); };
另一种方法可以用类似的方法来定义。 Foo
本身可以这样定义:
// foo/index.js function Foo() { } Foo.prototype.methodA = require('./foo.a'); Foo.prototype.methodB = require('./foo.b'); module.exports = Foo;
现在我们可以像这样使用Foo
:
// main.js var Foo = require('./foo'); var foo = new Foo(); foo.methodA(); // 'Method A' foo.methodB(); // 'Method B'
这个解决scheme比你自己的一个优点是, Foo
所有方法都在一个地方声明,即在foo/index.js
,但是在其他地方定义。 立即清楚地看一个文件Foo
有什么方法,没有任何杂乱的实现。
每个文件有多个方法
在这种情况下,我倾向于使用mixin模式。 这是目录结构:
/foo bar.js baz.js index.js /utils extend.js mixin.js main.js
从一个扩展一个对象的函数开始,包括getters / setter和维护相同的属性描述符 。
// utils/extend.js module.exports = function extend(target, source) { var names = Object.getOwnPropertyNames(source); var len = names.length; for (var i = 0; i < len; i++) { var name = names[i]; var descriptor = Object.getOwnPropertyDescriptor(source, name); Object.defineProperty(target, name, descriptor); } };
一个mixin只是这样做的两个对象的原型:
// utils/mixin.js var extend = require('./extend'); module.exports = function mixin(target, source) { extend(target.prototype, source.prototype); };
现在我们可以像这样定义Bar
基类:
// foo/bar.js function Bar(a, b) { this.a = a; this.b = b; } Bar.prototype.methodA = function() { console.log(this.a); }; Bar.prototype.methodB = function() { console.log(this.b); }; module.exports = Bar;
Baz
可以被类似地定义。 那么可以这样定义Foo
,它可以这样定义:
// foo/index.js var Bar = require('./bar'); var Baz = require('./baz'); var mixin = require('../utils/mixin'); function Foo(a, b, c, d) { Bar.call(this, a, b); Baz.call(this, c, d); } mixin(Foo, Bar); mixin(Foo, Baz); module.exports = Foo;
我们可以像这样使用它:
// main.js var Foo = require('./foo'); var foo = new Foo('one', 'two', 'three', 'four'); foo.methodA(); // 'one' foo.methodB(); // 'two' foo.methodC(); // 'three' foo.methodD(); // 'four'
这种方法的一个优点是我们可以自己或者扩展其他类别的Bar
或者Baz
。 而且,每个都有自己的构造函数的事实让我们可以在定义它们的文件中声明它们的依赖关系,而不必记住在Foo
构造函数中分配一个this.a
属性。