如何“子类化”一个node.js模块
我多年来一直是Perl编程人员,但也有C ++的背景,所以我来自“经典”面向对象的背景,现在正在学习node.js。 我刚刚阅读了“面向对象的JavaScript原则” ,它很好地向像我这样有经典头脑的人解释面向对象的JS概念。 但我留下了一个问题,具体涉及到node.js和inheritance。 如果我还在用“古典”词汇来解释我的问题,请原谅我。
让我们假设我有一个模块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"
这甚至有可能吗? 如果是这样,我错过了什么?
或者这是一种反模式? 或者根本不可能? 我该怎么做呢?
以下是我如何做到的,以覆盖请求模块中的一个方法。 警告 :许多节点模块的扩展devise很差,包括请求,因为它们在构造函数中做太多东西。 不只是一个巨大的参数选项,而是启动IO,连接等。例如,请求将http连接(最终) 作为构造函数的一部分 。 没有明确的.goDoIt()
或.goDoIt()
方法。
在我的例子中,我想使用querystring而不是qs格式化表单。 我的模块巧妙地命名为“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大师,所以可能有更好的方法…
作为参考,我提出了我的示例代码问题的具体解决scheme如下:
在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;
然后在我的testing脚本中:
var bar = require('lib/bar.js'); bar.foo(); // Output "Foo was called" bar.bar(); // Output "Bar was called"