Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between `util.inherits` and extending the prototype in NodeJS

I have been using Node since 0.11/0.12 so correct me if this is a matter of coming 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 common 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?

like image 777
Jorge Bucaran Avatar asked Apr 08 '15 05:04

Jorge Bucaran


People also ask

What is inheritance in JS?

Inheritance enables you to define a class that takes all the functionality from a parent class and allows you to add more. Using class inheritance, a class can inherit all the methods and properties of another class. Inheritance is a useful feature that allows code reusability.

Does node js support inheritance?

By default, each class in Node. js can extend only a single class. That means, to inherit from multiple classes, you'd need to create a hierarchy of classes that extend each other.

How to achieve inheritance in js?

To create a class inheritance, use the extends keyword.

Does JavaScript support multiple inheritance?

JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.


1 Answers

If 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)
like image 68
HMR Avatar answered Sep 29 '22 15:09

HMR