node.js对象继承覆盖对象方法

时间:2015-03-03 05:28:41

标签: node.js prototypal-inheritance

我正在尝试移植Java应用程序以在node.js中使用,并且遇到了Object继承的问题。我有一个基础对象HVal和2个子类,HBin和HBool。当我尝试同时使用HBin和HBool时,加载的第一个对象将被加载的第二个对象覆盖,即使它们被分配给不同的变量。任何人都知道这里发生了什么。

HVal.js

/** Package private constructor */
function HVal() {};

/** Abstract functions that must be defined in inheriting classes 
 * hashCode: int - Hash code is value based
 * toZinc: String - Encode value to zinc format
 * equals: boolean - Equality is value based
 */

/** String - String format is for human consumption only */
HVal.prototype.toString = function() { return this.toZinc(); };

/** int - Return sort order as negative, 0, or positive */
HVal.prototype.compareTo = function(that) { return this.toString().localeCompare(that); };

/** boolean - check for type match */
HVal.prototype.typeis = function (check, prim, obj) { return typeof(check)==prim || check instanceof obj; };

/** Add hashCode function to Javascript String object */
String.prototype.hashCode = function() {
  var hash = 0, i, chr, len;
  if (this.length == 0) return hash;
  for (i = 0, len = this.length; i < len; i++) {
    chr   = this.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
};

/** Export for use in other modules */
module.exports = new HVal();

HBin.js

var hval = require('./HVal');

/** Private constructor */
function HBin(mime) { 
  /** MIME type for binary file */
  this.mime = mime; 
};
HBin.prototype = hval;

/** Construct for MIME type */
HBin.prototype.make = function(mime) {
  if (!hval.typeis(mime, 'string', String) || mime.length == 0 || mime.indexOf('/') < 0)
    throw new Error("Invalid mime val: \"" + mime + "\"");
  return new HBin(mime);
};

/** int - Hash code is based on mime field */
HBin.prototype.hashCode = function() { return mime.hashCode(); };

/** String - Encode as "Bin(<mime>)" */
HBin.prototype.toZinc = function()  {
  var s = "Bin(";
  for (var i=0; i<this.mime.length; ++i)
  {
    var c = this.mime.charAt(i);
    if (c > 127 || c == ')') throw new Error("Invalid mime, char='" + c + "'");
    s += c;
  }
  s += ")";
  return s.toString();
};

/** boolean - Equals is based on mime field */
HBin.prototype.equals = function(that) {
  if (!typeOf(that) == HBin) return false;
  return this.mime === that.mime;
};

/** Export for use in other modules */
module.exports = new HBin();

HBool.js

var hval = require('./HVal');

/** Private constructor */
function HBool(val) { 
  /** Boolean value */
  this.val = val;
};
HBool.prototype = hval;

/** Construct from boolean value */
HBool.prototype.make = function(val) {
  if (!hval.typeis(val, 'boolean', Boolean))
    throw new Error("Invalid boolean val: \"" + val + "\"");
  return new HBool(val); 
};

/** int - Hash code is same as java.lang.Boolean */
HBool.prototype.hashCode = function() { return this.val ? 1231 : 1237; };

/** String - Encode as T/F */
HBool.prototype.toZinc = function() { return this.val ? "T" : "F"; };

/** boolean - Equals is based on reference */
HBool.prototype.equals = function(that) { return this === that; };

/** String - String format is for human consumption only */
HBool.prototype.toString = function() { return this.val ? "true" : "false"; };

/** Export for use in other modules */
module.exports = new HBool();

index.js

var hbin = require('./HBin');
var hbool = require('./HBool');

console.log('BIN: ' + hbin.make("test/test").toString());
console.log();
console.log('T: ' + hbool.make(true).toString());
console.log('F: ' + hbool.make(false).toString());

输出 - 在第一个console.log

上失败
HBool.js:19
    throw new Error("Invalid boolean val: \"" + val + "\"");
Error: Invalid boolean val: "test/test"
    at HVal.HBool.make (HBool.js:19:11)
    at Object.<anonymous> (index.js:4:28)
    ...

1 个答案:

答案 0 :(得分:1)

问题与你如何从模块导出以及如何在继承时分配原型以及问题是微妙的有关。这里有几件事情要发生。首先,module.exports缓存模块,所以每次都这样做:

var hval = require('./HVal');

每次都会获得完全相同的HVal实例化对象,并且您永远不能创建不同的对象,因为您没有导出构造函数。这是所有模块的问题。您应该导出构造函数,并让模块的用户使用new实际创建对象的新实例。

您可以通过更改:

来实现
module.exports = new HVal();

为:

module.exports = HVal;

然后当你require()时,你就得到了构造函数:

var HVal = require('./HVal');
var HBool = require('./HBool');

然后,你可以像这样创建一个HBool对象:

var hbool = new HBool();

当你分配类似的东西时,这个问题似乎弄乱了你的继承:

HBool.prototype = hval;

如果您导出构造函数本身然后更改上面的原型赋值以使用Object.create,那么问题就完全解决了:

HBool.prototype = Object.create(HVal.prototype);

你可以在这里看到一个有效的演示(删除模块以使演示更容易展示):http://jsfiddle.net/jfriend00/ty5wpkqm/


我还对代码进行了另一次修正。而不是:

if (!hval.typeis(mime, 'string', String) || mime.length == 0 || mime.indexOf('/') < 0)

我将其更改为实际使用此对象上的继承方法:

if (!this.typeis(mime, 'string', String) || mime.length == 0 || mime.indexOf('/') < 0)

这是在当前对象上调用方法的正确方法(甚至是继承的方法)。现在,这恰好是一个静态方法(它根本不使用实例,所以你可以完全将它从对象上移开,但是因为你已经在对象上声明它,你应该将它称为this.typeis()


我还注意到您的.equals()方法不正确。你有这个:

/** boolean - Equals is based on mime field */
HBin.prototype.equals = function(that) {
  if (!typeOf(that) == HBin) return false;
  return this.mime === that.mime;
};

首先,您是否创建了一个名为typeOf()的新全局函数? Javascript中的内置机制是小写typeof。第二关,typeof(that)永远不会是HBin。 Javascript中的对象不会报告类似的类型。对象将报告typeof(that) === "object"。您也许可以使用instanceof

/** boolean - Equals is based on mime field */
HBin.prototype.equals = function(that) {
  return that instanceof HBin && this.mime === that.mime;
};