I have been using Node since 0.11/0.12 so correct me if this is a matter of ing relatively late to the party.
I am trying to understand the difference between using util.inherits(Son, Dad)
and simply extending the prototype of Son.prototype = [new] Dad()
.
For this example I am subclassing a Transform stream using util.inherits
first:
var util = require('util')
var Transform = require('stream').Transform
util.inherits(TStream, Transform)
function TStream () {
Transform.call(this)
}
TStream.prototype._transform = function(chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
}
process.stdin.pipe(new TStream()).pipe(process.stdout)
The above seems to be the most mon way to go about this in Node. The following (extending the prototype) works just as well (seemingly), and it's simpler:
function TStream() {}
TStream.prototype = require("stream").Transform()
TStream.prototype._transform = function (chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
}
process.stdin.pipe(new TStream()).pipe(process.stdout)
For the record, I know there is through2
, which has a very simple interface, and do help reducing a few lines of code (see below), but I am trying to understand what is going under the hood, hence the question.
var thru = require("through2")(function (chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
})
process.stdin.pipe(stream).pipe(process.stdout)
So, what are the differences between util.inherits
and extending the prototype in Node?
I have been using Node since 0.11/0.12 so correct me if this is a matter of ing relatively late to the party.
I am trying to understand the difference between using util.inherits(Son, Dad)
and simply extending the prototype of Son.prototype = [new] Dad()
.
For this example I am subclassing a Transform stream using util.inherits
first:
var util = require('util')
var Transform = require('stream').Transform
util.inherits(TStream, Transform)
function TStream () {
Transform.call(this)
}
TStream.prototype._transform = function(chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
}
process.stdin.pipe(new TStream()).pipe(process.stdout)
The above seems to be the most mon way to go about this in Node. The following (extending the prototype) works just as well (seemingly), and it's simpler:
function TStream() {}
TStream.prototype = require("stream").Transform()
TStream.prototype._transform = function (chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
}
process.stdin.pipe(new TStream()).pipe(process.stdout)
For the record, I know there is through2
, which has a very simple interface, and do help reducing a few lines of code (see below), but I am trying to understand what is going under the hood, hence the question.
var thru = require("through2")(function (chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
})
process.stdin.pipe(stream).pipe(process.stdout)
So, what are the differences between util.inherits
and extending the prototype in Node?
-
First of; you should not set the prototype of Child to an instance of Parent as it shows a lack of understanding what prototype is. Prototype is shared and Parent may have instance specific members that end up on Child.prototype. If these members are mutable and you don't re use Parent constructor (doing
Parent.call(this)
in Child constructor) you will have Child instances mutating a shared member that should be instance specific. UseChild.prototype = Object.create(Parend.prototype)
instead. – HMR Commented Apr 8, 2015 at 7:56
1 Answer
Reset to default 8If this is the implementation of util.inherits it only does the following for you:
Child.super_ = Parent;
//set prototype using Object.create
Child.prototype = Object.create(Parent.prototype, {
constructor: {//repair the prototype.constructor
value: Child,
enumerable: false,
writable: true,
configurable: true
}
This is not a problem in Nodejs but in browsers that don't support a second argument to Object.create (because the polyfil does not allow it) you can repair the constructor in the following way:
Child.prototype = Object.create(Parent.prototype);//if you polyfilled Object.create
//Child.prototype.constructor is now Parent so we should repair it
Child.prototype.constructor = Child;
The extra thing it does is setting Child.super_ so in Child you can do:
function Child(){
Child.super_.call(this);//re use parent constructor
//same as Parent.call(this);
}
For more information on prototype and constructor functions you can read this answer.
According to the following, you are sub classing Transform incorrectly:
In classes that extend the Transform class, make sure to call the constructor so that the buffering settings can be properly initialized.
So the correct code should call it's constructor (you are not calling Transform with new but maybe the constructor has a way of handling faulty calls).
var Transform = require("stream").Transform;
function TStream() {
Transform.call(this);//you did not do that in your second example
}
//your code sets prototype to an INSTANCE of Transform
// and forgets to call the constructor with new
//TStream.prototype = require("stream").Transform()
TStream.prototype = Object.create(Transform.prototype);
TStream.prototype.constructor = TStream;
TStream.prototype._transform = function (chunk, encoding, done) {
this.push(/* transform chunk! */)
done()
}
process.stdin.pipe(new TStream()).pipe(process.stdout)