Node.js奇怪的原型继承

时间:2014-05-12 18:43:20

标签: javascript node.js inheritance prototypal-inheritance

我一直在跟随Manuel Teixiera的 Hands-On Node.js ,我在通过Event Emitter章节时偶然发现了这种奇怪的行为。

作者建议的代码包含以下内容:

var EventEmitter = require("events").EventEmitter;
var util = require ("util");

var MyClass = function() {};
util.inherits(MyClass, EventEmitter);
var instance = new MyClass();
instance.on("custom", function() {
   console.log("Holo");
});

instance.emit("custom");*/

哪个输出" Holo"正好。但是,我还阅读了有关如何使用new Function();是一种反模式的主题的文档和SO questions,这些反模式面对javascript对原型继承的预期用途。 This article by David Walsh说明了在js上强制经典继承和使用其原型继承功能之间的区别。

所以,我尝试通过重写它来修改我的代码:

var EventEmitter = require("events").EventEmitter;
var clock = {};
util.inherits(clock, EventEmitter);
clock.on("custom", function(){
    console.log("Holo");
});
clock.emit("custom");

我收到错误TypeError: Object object has no method 'on'。我不明白为什么会这样,因为我用util.inherit()帮助器创建了时钟对象。使用var clock = Object.create(EventEmitter)的相同代码也无效。

我可以让代码工作的唯一例子是:

var EventEmitter = require("events").EventEmitter;
var util = require("util");
var clock = {};
util.inherits(clock, EventEmitter);
clock.prototype.on("custom", function(){
    console.log("Holo");
});
clock.emit = function(){
        clock.prototype.emit("custom");
}
clock.emit();

这输出" Holo"正好。问题是,我不明白为什么我需要访问原型来设置事件监听器或发出一个事件,据说,我让clock变量委托它的方法到EventEmitter对象,所以如果没有原型符号,它们应该可以正常工作。

你能帮帮我吗?

2 个答案:

答案 0 :(得分:3)

根据node.js docs

  

<强> util.inherits(constructor, superConstructor)

     

将原型方法从一个构造函数继承到另一个构造函数。构造函数的原型将被设置为从superConstructor创建的新对象。

您正在传入util.inherits设计为期望构造函数的对象。 util.inherits通过重新定义构造函数的prototype属性来运行,该属性对由该构造函数构造的实例具有原型链含义。您已传入一个对象,而不是构造函数,该对象的prototype属性已更改。这对任何事都没有任何影响:你刚刚在名为&#34; prototype&#34;的对象上创建了一个属性,这就像你做了一个属性一样特别名为foobar的对象。

有一种思想学派避免使用new(支持调用Object.create的工厂函数 - 请参阅Is JavaScript's "new" keyword considered harmful?的讨论),但显然是实施的API设计人员util.inherits不会分享该观点。

但是,您尝试的Object.create(EventEmitter)确实不正确,因为Object.create需要原型对象,而不是构造函数。相反,你做Object.create(EventEmitter.prototype)。这与调用new EventEmitter()相同,只是Object.create变体不会调用EventEmitter构造函数。

答案 1 :(得分:0)

我不知道Node的继承的实现,但是我想它只是将成员从第二个添加到第一个操作数的原型。因此,它假定它将被传递给构造函数。但传递一个空对象不会引发异常。

您需要传递构造函数并使用new调用它。这很正常,绝对没问题。

另外,你在哪里知道使用new和prototypes在某种程度上相互排斥,或者要避免使用New?听起来你可能想要多练习一下你的JavaScript OOP。