0

I'm trying to use prototypal inheritance, but I'm having trouble.

This doesn't work

var Parent = function(){
}

var Child = function(){
    this.__proto__ = new Parent();
}

var child = new Child();

console.log(child instanceof Child) //logs false

But this does

var Parent = function(){
}

var Child = function(){

}
Child.prototype = new Parent();

var child = new Child();

console.log(child instanceof Child) // logs true

The only reason why I want the first option is so that I can leverage the parent's constructor. I'm guessing this is the problem, but I'm not that great at javascript. How do I make this work?

Josh C.
  • 4,303
  • 5
  • 30
  • 51
  • When you say `this.__proto__ = new Parent()` you're saying "Okay new object, stop being a `Child` and start being a `Parent` instead," so it's not surprising that the object is no longer and instance of Child. – apsillers Nov 27 '13 at 15:47
  • @apsillers is that because of `this`? Why doesn't the second method do the same thing then? Is it because I am not in the scope of `new Child` when I set the prototype? – Josh C. Nov 27 '13 at 15:50
  • Ah, I understand your confusion now; I'll update my answer. – apsillers Nov 27 '13 at 15:54
  • 1
    Hi Josh, it's a little late but maybe the following answer can give you a better understanding of prototype (shared members) and `this` (instance members): http://stackoverflow.com/a/16063711/1641941 – HMR Nov 27 '13 at 23:51
  • but this is actually Classical Inheritance not Prototypal Inheritance. – Fahmi Mar 31 '17 at 12:31

1 Answers1

2

The better way to do this is to call the Parent constructor on this:

var Child = function(){
    Parent.call(this);
}

That way, the Parent constructor code runs with its this set to the this in the Child constructor, but you don't change the __prototype__ of this.

Your two examples do produce a child instance that is structurally the same. However, the main difference is that in your first example, Child.prototype != child.__proto__. Although it is true that Child.prototype and child.__proto__ are both objects with a __proto__ of Parent.prototype, they are not the exact same object, so instanceof fails.

You may also want to do Child.prototype = Object.create(Parent.prototype); so that Child instances have access to Parent's prototype method. (Currently you don't have any methods on Parent.prototype, but maybe you will someday.)

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • It is entirely my intention to have common methods on the Parent or its prototype – Josh C. Nov 27 '13 at 15:53
  • Don't I need to set the result of `Parent.call(this)` to something on Child? And, does `Child.prototype = Object.create(Parent.prototype);` replace `Child.prototype = new Parent();`? – Josh C. Nov 27 '13 at 15:55
  • 1
    @JoshC. No, `Parent.call(this)` stands on its own, because it mutates `this`. The `Parent` constructor does things like `this.foo = 5`, so after `Parent.call(this)` completes, your `this` has a `foo` property. – apsillers Nov 27 '13 at 15:59
  • Then how do I pass args to the parent constructor from the child? Do I simply list them after `this` like `Parent.call(this, arg0, arg1, etc.)`? – Josh C. Nov 27 '13 at 16:01
  • 1
    @JoshC. Yes, you should do `Child.prototype = Object.create(Parent.prototype);` instead of `Child.prototype = new Parent();` Here's an example of why: http://stackoverflow.com/a/20201556/710446. Basically, the `Parent` constructor might do things per-instance (like set a unique ID), and you don't want all your `Child` instances sharing a single instance ID. – apsillers Nov 27 '13 at 16:02
  • Yes, but I'm thinking part of my parent's common behavior but unique per instance data would be driven in part by args passed to the constructor. How do I accomplish that? – Josh C. Nov 27 '13 at 16:04
  • 1
    @JoshC. Yes, that's the [correct way to use `call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call). You could also use [`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) to pass in an array of arguments, like `Parent.apply(this, [arg1, arg2, arg3])`. This is especially handy if you want to pass in all of `Child`'s arguments to `Parent`, by doing `Parent.call(this, arguments)`. – apsillers Nov 27 '13 at 16:05