Domanda

I've been trying to understand why I see code like this in node all the time:

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

function MyStream() {
    events.EventEmitter.call(this);
}

util.inherits(MyStream, events.EventEmitter);

MyStream.prototype.write = function(data) {
    this.emit("data", data);
}

I went to the documentation in order to better understand.

util.inherits(constructor, superConstructor)

The prototype of constructor will be set to a new object created from superConstructor.

As an additional convenience, superConstructor will be accessible through the constructor.super_ property.

From that I assumed that meant that all util.inherits does is this:

exports.inherits = function (constructor, superConstructor) {
    constructor.super_ = superConstructor;
    constructor.prototype = new superConstructor();
}

Seemed to make sense to me, but then I noticed in the MyStream constructor they invoke event.EventEmitter.call(this); so that the EventEmitter constructor runs on the instance of MyStream being created. I was totally confused by this since constructor.prototype = new superConstructor(); should be all it needed right? Well I went to the source and found the actual function signature.

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

Once I saw this I got totally confused while trying to figure out what Object.create is doing here. Why is it doing this instead of just new superCtor()? I tried looking at the documentation for Object.create but I'm still confused. Let me try and see if I can articulate what I think is going on and you guys can correct me :)

The first argument to Object.create(proto [, propertiesObject ]) is the prototype that you want this new object to have. I guess this is just easier than the classic method of defining a constructor and setting its prototype property? The second argument is a simple hash with properties on it that should be added to the newly created object that it will return? So, this...

var myInstance = Object.create(somePrototype, { someProp: someVal, someProp2: someVal2);

...instead of this?

function MyClass () {
    this.prop = someVal;
    this.prop2 = someVal2;
    // etc
}
MyClass.prototype = somePrototype;
var myInstance = new MyClass();

I'm not sure if my understanding of Object.create is totally accurate so hopefully you guys can clarify. Assuming that I now understand Object.create why then does the util.inherits function not look like this?

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

To Summarize

Wouldn't the new superCtor eliminate the need to do events.EventEmitter.call(this) inside of MyStream? Why is it so important that we make the prototypes the same and then run the EventEmitter constructor on the actual instance that MyStream is creating instead of just having the prototype be an actual instance of EventEmitter?

Also, what is the purpose of adding a constructor property to ctor's prototype? Is that a JavaScript thing I don't know about?

È stato utile?

Soluzione

First parent may require arguments. When setting up Child.prototype you are defining the object and may not be ready to create instances yet.

Second parent instance specific values (this.someval) are put on the child's prototype and are then either shared among all child instances or become useless when Parent.apply(this,arguments) executes in the child's body and shadows them.

More info on constructor functions and prototype here : https://stackoverflow.com/a/16063711/1641941

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top