如何"子类" node.js模块

时间:2014-10-10 22:35:29

标签: node.js inheritance node-modules

我多年来一直主要是Perl编码员,但也有C ++背景,所以我来自一个经典的" OO背景,现在学习node.js.我刚读完The Principles of Object-Oriented JavaScript,它很好地向像我这样有经典思想的人解释了OO的JS概念。但是我留下了一个问题,特别是与node.js和继承有关。请原谅我,如果我还在使用" classic"词汇来解释我的问题。

假设我有一个模块lib/foo.js

function foo() {
    console.log('Foo was called');
}

module.exports.foo = foo;

我想"子类"这在另一个模块lib/bar.js中:

var foo = require('foo.js');

// Do some magic here with *.prototype, maybe?

function bar() {
    console.log('Bar was called');
}

module.exports.bar = bar;

这样我的主脚本可以这样做:

var bar = require('lib/bar.js');

bar.foo(); // Output "Foo was called"
bar.bar(); // Output "Bar was called"

这甚至可能吗?如果是这样,我错过了什么?

或者这是一种反模式?或者根本不可能?我该怎么做呢?

2 个答案:

答案 0 :(得分:2)

这是我如何做到的,以覆盖request module中的一种方法。 警告:许多节点模块的扩展设计很差,包括请求,因为它们在构造函数中做了太多的事情。不仅仅是一个巨大的参数选项,而是启动IO,连接等。例如,请求将http连接(最终)作为构造函数的一部分。没有明确的.call().goDoIt()方法。

在我的示例中,我想使用查询字符串而不是qs来格式化表单。我的模块巧妙命名为#34; MyRequest"。在名为myrequest.js的单独文件中,您有:

var Request = require('request/request.js');
var querystring = require('querystring');

MyRequest.prototype = Object.create(Request.prototype);
MyRequest.prototype.constructor = MyRequest;

// jury rig the constructor to do "just enough".  Don't parse all the gazillion options
// In my case, all I wanted to patch was for a POST request 
    function MyRequest(options, callbackfn) {
        "use strict";
        if (callbackfn)
           options.callback = callbackfn;
        options.method = options.method || 'POST';          // used currently only for posts
        Request.prototype.constructor.call(this, options);  
           // ^^^  this will trigger everything, including the actual http request (icky)
           // so at this point you can't change anything more
    }

    // override form method to use querystring to do the stringify
    MyRequest.prototype.form = function (form) {
     "use strict";
        if (form) {
            this.setHeader('content-type', 'application/x-www-form-urlencoded; charset=utf-8');
            this.body = querystring.stringify(form).toString('utf8');
  // note that this.body and this.setHeader are fields/methods inherited from Request, not added in MyRequest.
            return this;
        }

        else
           return Request.prototype.form.apply(this, arguments);
    };

然后,在您的应用程序中,而不是

var Request = require("request");
Request(url, function(err, resp, body)
  {
      // do something here
   });
你去了

var MyRequest = require("lib/myrequest");
MyRequest(url, function(err, resp, body)
  {
      // do that same something here
   });

我不是JavaScript大师所以可能有更好的方法......

答案 1 :(得分:0)

作为参考,我提出的具体解决方案是我的示例代码问题:

lib/foo.js

var Foo = function() {}

Foo.prototype.foo = function() {
    console.log('Foo was called!');
};

module.exports = new Foo;

lib/bar.js

var foo = require('./foo.js');

var Bar = function() {}

Bar.prototype = Object.create(foo.__proto__);
Bar.prototype.constructor = Foo;

Bar.prototype.bar = function() {
    console.log('Bar was called!');
};

module.exports = new Bar;

然后在我的测试脚本中:

var bar = require('lib/bar.js');

bar.foo(); // Output "Foo was called"
bar.bar(); // Output "Bar was called"