【问题标题】:Node.js weird prototypical inheritanceNode.js 奇怪的原型继承
【发布时间】:2014-06-30 06:07:05
【问题描述】:

我一直在关注 Manuel Teixiera 的 Hands-On Node.js,在阅读事件发射器一章时偶然发现了这种奇怪的行为。

作者建议的代码是这样的:

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”就好了。但是,我还阅读了文档和SO questions,主题是使用new Function(); 是一种反模式,它违背了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 对象的方法,所以他们应该没有原型符号也能正常工作。

你能帮帮我吗?

【问题讨论】:

    标签: javascript node.js inheritance prototypal-inheritance


    【解决方案1】:

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

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

    另外,您从哪里得知使用 new 和原型在某种程度上是相互排斥的,或者应该避免使用 New?听起来您可能想多练习一下 JavaScript OOP。

    【讨论】:

    • 这并不是说使用 new 和原型是相互排斥的,只是在我到目前为止阅读的文档和讨论中,包括 @apsillers 引用的那个,构造函数用于继承使得代码是,恕我直言,混淆且难以理解。我并不是说这不好,显然 Node.js api 的创建者认为是这样。这只是我觉得很难拼凑起来的东西。诚然,我对 JS 很陌生。
    • @EduardodeLuna - Aspilers 引用的文档抱怨构造函数如果调用不正确,将污染全局命名空间。就这样。与“面对原型继承”无关(新的对象仍然有原型),而且我看不到任何关于惯用 JavaScript 的“混淆”。您无法避免使用 New - 您不能在没有构造函数的情况下在 JavaScript 中使用私有对象变量、访问器或受保护的对象。没有封装的 OOP 实际上毫无意义。
    【解决方案2】:

    根据node.js docs

    util.inherits(constructor, superConstructor)

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

    您正在传递一个对象,其中 util.inherits 被设计为期望构造函数。 util.inherits 通过重新定义构造函数的 prototype 属性进行操作,该属性对该构造函数构造的实例具有原型链含义。您传入的不是构造函数,而是一个对象,该对象的prototype 属性已更改。这对任何事情都没有影响:您刚刚在名为“prototype”的对象上创建了一个属性,这与您在名为 foobar 的对象上创建了一个属性一样特别。

    有一种思想流派避免使用new(支持调用Object.create的工厂函数——参见Is JavaScript's "new" keyword considered harmful?的讨论),但显然实现util.inherits的API设计者不分享那个观点。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      • 2015-07-07
      • 1970-01-01
      相关资源
      最近更新 更多