3

I have the following simple inheritence pattern and I would like to know if it's ok to call methods the way i do from within the constructor function (basically speaking, using this instead of "super prototype".

Parent class, Pet

function Pet(name) {
  this.name = name;
  this.nickname = name;

  this.adopt();
}

Pet.prototype.adopt = function() {
  this.nickname = 'Cutty ' + this.name;
}

Pet.prototype.release = function() {
  this.nickname = null;
}

Pet.prototype.cuddle = function() {
  console.log(this.name + ' is happy');
}

Subclass, Lion

function Lion(name) {
  Pet.prototype.constructor.apply(this, arguments); // super(name)
  this.cuddle();
  this.release();
}
Lion.inherits(Pet);

Lion.prototype.adopt = function() {
  // DTTAH
}

Lion.prototype.release = function() {
  Pet.prototype.release.call(this);
  console.log('Thanks for releasing ' + this.name);
}

inherits helper (polyfills are bad I know)

Function.prototype.inherits = function(Parent) {
  function ProtoCopy() {}
  ProtoCopy.prototype = Parent.prototype;

  this.prototype = new ProtoCopy();
  this.prototype.constructor = this;
}

My pets are instantiated like so var lion = new Lion('Simba')

In Lion constructor,
Can I keep using this when calling sub/parent class methods ? Or should I use methods from parent prototype directly ? (like pseudo call to super() or in release())

Reasons why I am asking are:

  • this substitution at runtime
  • constructor property not always what we are thinking (from what I read here and there)

I am not sure how these things can influence the resulting object.

Thanks for your enlightenment !

10
  • 1
    Your inherits function has side-effects, I'd recommend using Object.create. Commented Jul 20, 2015 at 19:09
  • You should omit the .prototype.constructor part everywhere. Commented Jul 20, 2015 at 19:11
  • That Pet.prototype.constructor.release(); super call is wrong. Your probably meant Pet.prototype.release.call(this); Commented Jul 20, 2015 at 19:11
  • I don't want to provide this as a full answer, but rather a piece of advice to consider having a look at Klass.js github.com/ded/klass - it allows calling this.super() with ease. Commented Jul 20, 2015 at 19:51
  • @elclanrs what kind of side effects ? this was the part i was the most confident on ! Commented Jul 20, 2015 at 21:43

2 Answers 2

1

What is the difference between using this.fn() and MyClass.prototype.fn.call(this) in a constructor function?

This is not specific to constructor functions, it's the same in all functions (methods) that are called on instances.

Indeed there's not much difference apart from the character count when this.fn === MyClass.prototype.fn, and they would behave exactly the same. However, this assumption is not always true - this might not inherit from MyClass.prototype directly, but rather be a subclass instance, and that subclass might have overwritten the this.fn method.

So which one is correct? Both, in fact. If you know the difference, you can choose the appropriate one for your case. Other languages have different default expectations here, see also for calling static methods.

Notice that you cannot replace the class reference by this.constructor, which would be overwritten as well. In a reasonable setup1, this.fn() would be always equivalent to this.constructor.prototype.fn.call(this).

This is similar to the reason why super calls must explicitly reference the super class, and not depend on instance properties (such as this.constructor, this.super or anything similar).

1: Where this.fn is a usual method inherited from the prototype, not an own instance-specific one, and where every prototype has the .constructor pointing to the respective constructor whose .prototype it is.

Sign up to request clarification or add additional context in comments.

2 Comments

About this part: "Notice that you cannot replace the class reference by this.constructor, which would be overwritten as well" Are you talking about an explicit and targeted overwrite of the constructor property or a side effect of some other operation ?
Yes, when subclassing the .constructor is explicitly overwritten. You'll have to use Pet, not this.constructor, because the latter might refer to Lion.
1

Simplifying the problem, consider the following code in ES6:

class Pet {
  constructor (name) {
    this.name = name;
    this.talk();
  }
  talk () {
    console.log('My name is ' + this.name);
  }
}

class Lion extends Pet {
  constructor (name) {
    super(name);
  }
  talk () {
    super.talk();
    console.log('I am a lion.');
  }
}

would be equivalent to:

function Pet (name) {
  this.name = name;
  this.talk();
}
Pet.prototype.talk = function () {
  console.log('My name is ' + this.name);
};

function Lion (name) {
  Pet.call(this, name);
}

// inheritance:
Lion.prototype = Object.create(Pet.prototype);
Lion.prototype.constructor = Lion;

// override .talk
Lion.prototype.talk = function () {
  Pet.prototype.talk.call(this);
  console.log('I am a lion');
}

Running new Lion('Bobby') logs:

My name is Bobby
I am a lion

Further reading: http://eli.thegreenplace.net/2013/10/22/classical-inheritance-in-javascript-es5

2 Comments

isn't the inheritance part missing from your example ? I get lion instanceof Pet === false
@Jordan ahh, my bad, I forgot that part. There are two lines that will now return lion instanceof Pet to be true. It's in the article as well, just forgot it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.