如何在 node.js 中跨多个文件拆分类定义?

Posted

技术标签:

【中文标题】如何在 node.js 中跨多个文件拆分类定义?【英文标题】:How do I split a class definition across multiple files in node.js? 【发布时间】:2016-11-02 15:21:07 【问题描述】:

我对@9​​87654321@ 的类定义已经发展到我想将它拆分到多个文件中的程度。例如,我想要这样的东西:

// 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.exportrequire() 的正确组合是什么才能使上述代码正常工作?

【问题讨论】:

【参考方案1】:

更新答案

(对McMath's detailed answer 的完整支持——它的扩展性比下面的原始答案更好,并提供了更好地代码重用的机会。它促使我更新了这个答案。但是如果你不需要完整的 mixin那里支持的路线,这是一种干净简单的方法。)

修改technique suggested by Shaun Xu,您可以将主要类定义作为参数传递给require,该参数将在拆分文件中接收。

最好使用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

【讨论】:

【参考方案2】:

我会考虑两种解决方案,具体取决于我是想为每个文件定义一个方法还是将多个相关方法分组到一个文件中。

每个文件一个方法

从这样的目录结构开始:

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'

与您自己的解决方案相比,此解决方案的一个优点是Foo 的所有方法都在一个地方声明,即在foo/index.js 中,但在其他地方定义。看一个文件,Foo 有哪些方法,一目了然,而没有它们实现的所有混乱。

每个文件有多种方法

在这种情况下,我倾向于使用mixin 模式。目录结构如下:

/foo
  bar.js
  baz.js
  index.js
/utils
  extend.js
  mixin.js
main.js

从一个扩展一个对象到另一个对象的函数开始,包括 getter/setter 并保持相同的 property descriptor。

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

这种方法的一个优点是我们可以自己使用BarBaz 或扩展其他类。此外,每个都有自己的构造函数这一事实让我们可以在定义它们的文件中声明它们的依赖关系,而不是必须记住在 Foo 构造函数中分配 this.a 属性。

【讨论】:

以上是关于如何在 node.js 中跨多个文件拆分类定义?的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery SQL 中跨多个字段的拆分函数

在python中跨多个列表查找列的最小值

如何在 PHPUnit 中跨多个测试模拟测试 Web 服务?

在 DDP Pytorch Lightning 中跨 GPU 拆分训练数据

Node.js 组合来自多个文件的模块/导出

Javascript中跨多个文件的全局变量