3

I have the following:

function Person() {
  console.log('person');
}

function Player() {
  this.personConstructor();
}

Player.prototype = Person.prototype;
Player.prototype.constructor = Player;
Player.prototype.personConstructor = Person.prototype.constructor;

new Player();

The intent is to inherit from Person into Player then have that new child class call the parent's original constructor. However, this causes an infinite loop. What am I doing wrong and why is the loop happening?

2
  • 3
    Player.prototype = Person.prototype; should be Player.prototype = Object.create(Person.prototype); Commented Aug 9, 2014 at 17:04
  • 1
    ...this is because when you made Player.prototype a reference to Person.prototype and then assigned Player to Player.prototype.constructor, you were actually assigning it to Person.prototype.constructor. So then personConstructor was actually a reference to Player instead of Person, and so created the infinite call loop. Commented Aug 9, 2014 at 17:06

2 Answers 2

4

This line right here is your problem:

Player.prototype = Person.prototype;

You want the prototype for Player to inherit from Person's prototype, but not make them equal. Currently, your code makes the Player and Person prototypes reference equal, so any changes to Player.prototype also affect the Person.prototype (effectively making them indistinguishable).

You're looking for:

Player.prototype = Object.create(Person.prototype);

Object.create instantiates a new object with a given prototype without actually calling the constructor (unlike a regular new Person() call would do). This allows you to get a new object inheriting the Person prototype, which you can then modify for the specifics of a Player.

EDIT: As suggested in the comments by Siddarth, an even better solution would be to set the constructor through a property descriptor:

Player.prototype = Object.create(Person.prototype, {
    constructor: { value: Player }
});

This way, the newly created prototype will have its constructor property made non-configurable, non-enumerable and non-writable. This prevents you from accidentally changing it afterwards through an assignment (e.g. Player.prototype.constructor = Foo) and it won't show up in Object.keys or a for..in loop. Normally, this shouldn't matter much but it's a good practice.

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

3 Comments

I would make that Object.create(Person.prototype, { constructor: { value: Player } })
Also, don't forget to call the parent's constructor in the child's constructor.
@Siddharth Oh right, you can pass in a bunch of property descriptors to Object.create. I personally prefer using classical assignment or something like _.extend for adding properties to a prototype. Property descriptors may be better though, your solution prevents the prototype's constructor from (accidentally) getting changed later on. Thanks for the tip!
0
function Person(args) {
  console.log('person');
  args=args||{};
  this.name=args.name||"no name";
}

function Player(args) {
//  this.personConstructor();
// I prefer 
  Person.call(this,args);
}

Player.prototype = Object.create(Person.prototype);
Player.prototype.constructor = Player;

console.log(new Player());
console.log(new Player({name:"Jon"}));

It may be better to just re use Parent constructor with the following

Person.call(this,args);

Because if you use something like this.parent()... you'll get an infinite loop when you inherit 3 levels deep.

More on prototype and constructor functions here.

2 Comments

this.personConstructor() works fine, no need for .call if you're going to pass in the same this. However, Person.call(this,args) is indeed a more general solution which doesn't need the extra Player.prototype.personConstructor definition.
@MattiasBuelens Correct, I changed the answer.

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.