0

I'm learning myself JavaScript, but I'm confused about the whole prototyping and inheritance in JavaScript.

Example 1:

function MyClass()  {
    this.my_var =  "1";
}

function MyClass2()  {
    this.my_var2 = "2";
}

MyClass2.prototype = new MyClass();

class2 = new MyClass2();
console.log(class2.my_var);
console.log(class2.my_var2);

This is the easiest one to understand. the prototype of MyClass2 is a MyClass object, so it seems natural that class2 has access to its properties.

Example 2:

I wondered if it was possible to set the prototype in the constructor function itself:

function MyClass()  {
    this.my_var =  "1";
}

function MyClass2()  {
    this.my_var2 = "2";
    this.prototype = new MyClass();
}

class2 = new MyClass2();
console.log(class2.my_var);
console.log(class2.my_var2);

This doesn't seem to work however. my_var appears to be undefined.

Example 3:

Let's try another approach, this time using Object.create():

function MyClass()  {
    this.my_var =  "1";
}

function MyClass2()  {
    this.my_var2 = "2";
}

MyClass2.prototype = Object.create(MyClass);

class2 = new MyClass2();
console.log(class2.my_var);
console.log(class2.my_var2);

No luck either, my_var appears to be undefined.

Example 4:

This time, I'm using NodeJS "inherits()" function from the "util" module:

util = require("util");
function MyClass()  {
    this.my_var =  "1";
}

function MyClass2()  {
    this.my_var2 = "2";
}

util.inherits(MyClass2, MyClass);

class2 = new MyClass2();
console.log(class2.my_var);
console.log(class2.my_var2);

I understand why example 1 works, but I don't understand why 2,3 and 4 do not. I hope someone can explain me why that is the case.

4
  • You can use this.__proto__ = new MyClass(); Commented Jan 6, 2016 at 15:39
  • 2 doesn't work because this is just a regular object, so .prototype does nothing special. 3 doesn't work because you should be using Object.create(MyClass.prototype) and using .apply to in MyClass2 to invoke MyClass on this. Commented Jan 6, 2016 at 15:39
  • 1
    @jcubic that is probably not the best solution. Using Object.create seems more sensible. Commented Jan 6, 2016 at 15:40
  • @jcubic it is not advised to manipulate __proto__. Do it only for learning. Commented Jan 6, 2016 at 15:44

2 Answers 2

1

Example 2: this keyword is reference to instance of an object. That is object created with new. You can't set prototype in a constructor because object's prototype is used as a prototype for creating new object when using new keyword. So... MyClass's prototype is used when creating new object, and this references some object that is instanceof MyClass.

.prototype property is specific to function and it is an object that is copied to instanced object of that function/class.

Example 3: Object.create() creates object from another object, and you pass in function which may be an object but you get not clone of an object but of a function object. But you want object that is an instance of a function/class.

so if you type: Object.create(MyClass).__proto__ you'll see it is a function. __proto__ is special internal object prototype represents after evaluating your script. You can manipulate for experiments but it is not advised to manipulate it in production. You can fix this example by using new MyClass.

Example 4: You need to add MyClass.call(this); as first line in MyClass2 function.

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

Comments

0

The first is actually wrong, because you should be inheriting from MyClass's prototype, and not from an instance of it. Although this was commonly done in the past, it's a broken inheritance model that expects you to create an instance of an class before you can derive subclasses from it.

From there, it follows that the other examples are also wrong because in each case you're still inheriting from an instance (in cases two and three) or expecting that non-prototype properties of the base class will be visible in the derived class (case four).

The correct formulation for case three is:

function MyClass() {
}

MyClass.prototype.myMethod = function() { ... }

function MyClass2() {
    MyClass.call(this);     // invoke superclass constructor
}

// create a new (empty) prototype that chains to the superclass's
MyClass2.prototype = Object.create(MyClass.prototype);

// and reattach the constructor
MyClass2.prototype.constructor = MyClass2;

// now add methods to MyClass2
MyClass2.prototype.myMethod2 = function() { ... }

14 Comments

Why is the first one wrong? I don't think its a good approach, but he is inheriting from MyClass's prototype via the instance.
@squint it's wrong because it conflates the properties of that single instance with the methods that should be in its prototype. It also makes it impossible to invoke a superclass constructor properly.
That could be a way to set primitive defaults on MyClass2.prototype. Again, I wouldn't do it but with respect to how inheritance works, it's not incorrect. WRT calls to the superclass' constructor, did you mean the subclass?
@squint no, I meant the superclass - in my version here the derived class's constructor makes a call to the superclass's constructor. If you've derived from an instance there's no superclass constructor to call because the (singe) instance has already been constructed.
Okay, it seems that I'm even more confused than I initially thought. Since JS doesn't really have "classes", I was unaware that there are also constructors involved. So initialisation of an object occurs in two different places? constructor and prototype?
|

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.