util.inherits - 替代方案或解决方法

19

我是一个 Node 的 n00b,发现 util.inherits() 非常有用,只是它似乎会替换原始对象的整个原型。例如:

var myClass = function(name){
    this._name = name;  
};

myClass.prototype = {
    (...)
};

util.inherits(myClass, require('events').EventEmitter);

似乎会抹掉我的原型。

这给我带来了两个不便之处:
1 - 在调用 inherits 后,我必须声明并添加属性到我的原型中。

var myClass = function(name){
    this._name = name;  
};

util.inherits(myClass, require('events').EventEmitter);

myClass.prototype.prop1 = function(){...};
myClass.prototype.prop2 = function(){...};

而且,最重要的是,我认为我不能继承两个或更多不同的类。

有人能解释一下这是为什么,以及有什么好的方法可以解决这个问题吗?

谢谢


1
util.inherits() 不再推荐使用,现在应该使用 class 和 extends:https://nodejs.org/docs/latest/api/util.html#util_util_inherits_constructor_superconstructor - basickarl
5个回答

13

util.inherits()之后声明原型并没有意义。我猜测,util.inherits最初是一种仅用于内部使用的方法,仅为其最初预期使用情况量身定制,并在某个时候发布供普通用户使用。由于util模块是用纯JS编写的,因此非常容易实现自己版本的util.inherit,以保留您的原型。以下是原始的util.inherit源代码:

exports.inherits = function(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
};

至于多重继承,这将是一个更为困难的问题,因为JavaScript的原型继承并不适合于多重继承。每个实例只有一个内部的[[Prototype]]属性,它用于查找在实际实例中找不到的成员。你可以将两个独立的“父类”的原型合并为单个原型,但你将失去对它们的父级的继承,并且你将失去改变父级原型并让所有子类看到更改的能力。


好的,那么有没有一种类似于jQuery的$.extend的方法来扩展一个对象呢? - André Alçada Padez
谢谢,我会在有机会的时候尝试它。 - André Alçada Padez

9

在函数定义之后,你应该首先进行继承,然后再实现你的对象。同时,在你的类构造函数中不要忘记调用父类的构造函数。

Function A(y){
  this.y = x;
}

Function B(x,y){
  this.x = x;
  A.call(this,y);
}

util.inherits(B,A);

B.prototype.mythodA = function() {
    //do something
}

1
你没有理解重点。这正是他试图避免的事情(即每次想要向原型添加另一个方法时都要键入B.prototype.xxx)。 - jedmao

4
从node 5.0.0版本开始,util.inherits已经被改变,使用setPrototypeOf方法支持您所需的行为:

FirstBase.js

function FirstBase(firstBaseProp){
    this.firstBaseProp = firstBaseProp;
}

FirstBase.prototype.getFirstBaseProp = function(){
    return this.firstBaseProp;
};


module.exports = FirstBase;

SecondBase.js

var FirstBase = require('./FirstBase.js'),
    util = require('util');

function SecondBase(firstBaseProp, secondBaseProp){
    this.secondBaseProp = secondBaseProp;
    SecondBase.super_.apply(this, arguments);
}

SecondBase.prototype.getSecondBaseProp = function(){
    return this.secondBaseProp;
};

util.inherits(SecondBase, FirstBase);

module.exports = SecondBase;

ThirdBase.js

var SecondBase = require('./SecondBase.js'),
    util = require('util');

function ThirdBase(firstBaseProp, secondBaseProp, thirdBaseProp){
    this.thirdBaseProp = thirdBaseProp;
    ThirdBase.super_.apply(this, arguments);
}

ThirdBase.prototype.getThirdBase = function(){
    return this.thirdBaseProp;
};

util.inherits(ThirdBase, SecondBase);

module.exports = ThirdBase;

instance.js

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

var instance = new ThirdBase('first', 'second', 'third');

// With node < 5.0.0 (Object.create)
console.log(instance.getFirstBaseProp()); // first
console.log(instance.getSecondBaseProp()); // undefined
console.log(instance.getThirdBase()); // undefined

// With node >= 5.0.0 (Object.setPrototypeOf)
console.log(instance.getFirstBaseProp()); // first
console.log(instance.getSecondBaseProp()); // second
console.log(instance.getThirdBase()); // third

如果你正在运行一个支持setPrototypeOf的旧版本node(0.12.x支持),你可以直接exportutil.inherits并将其用作内部实用函数。


2

我非常希望得到相同的东西,但是我对扩展感到不满意,因此我创建了这个扩展来改进已经有用的util.inherits方法:

var util = require('util');

module.exports = {
    inherits : function(sub, sup, proto) {
        util.inherits(sub, sup);
        if (typeof proto !== 'undefined') {
            Object.keys(proto).forEach(function(key) {
                sub.prototype[key] = proto[key];
            });
        }
    }
};

我将这段代码放在我的项目的./util/index.js文件中,然后按照以下方式使用它:

var EventEmitter = require('events').EventEmitter;
var util = require('./util');

function Foo() {
    EventEmitter.call(this);
}

util.inherits(Foo, EventEmitter, {
    bar : function(){
        console.log(this instanceof EventEmitter); // true
    }
});

也许如果我发现它越来越稳定和有用,我会发布它。我只是刚刚自己实现了它,所以我正在测试它。
告诉我你的想法!
注意:这确实覆盖了类中定义的方法,使用在最后的proto散列表中定义的方法。请注意这一点。

谢谢,看起来差不多正确。将它推到Github上,这样社区就可以尝试它了。我只能在下周尝试它,但我会给你反馈。谢谢。 - André Alçada Padez

0

Inherits-ex库是一个浏览器友好的增强继承库,完全兼容标准的node.js继承方式,具备动态继承或创造继承的能力。

  • 静态继承
  • 支持多继承(继承链)
  • 随时继承 —— 你想要的
    • 在标准方式下,在继承之前不能声明方法/属性,否则会替换原型对象。
  • 重复继承检测
  • 支持Es6类
  • 更多辅助函数
    • isInheritedFrom(ctor, superCtor|superCtorName) 检查ctor是否从superCtor继承而来
    • mixin(ctor, superCtor|superCtor[]) 将SuperCtor的方法和属性混合到ctor中:将所有superCtor的属性(方法)克隆(复制)到ctor中。
    • isMixinedFrom
    • createCtor
    • createObject
    • createFunction

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接