Example 1:
function Rabbit(type) {
this.type = type;
}
Rabbit.prototype.speak = function(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
};
let weirdRabbit = new Rabbit("weird");
console.log(Rabbit.prototype);
Example 2:
class Rabbit {
constructor(type) {
this.type = type;
}
speak(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
}
let weirdRabbit = new Rabbit("weird");
console.log(Rabbit.constructor.prototype);
Please take a look at the code in the pictures above.
The code in both apparently does the same thing. I read in a book that said when we create a class
using class
keyword the methods and other properties are all packaged into that constructor’s prototype, just like the way the code in the first image does. But, we can see the difference in both representations on the right.
And, when I type Rabbit.prototype in the console - the first code gives Rabbit { speak: [Function] }
and the second one gives Rabbit {}
as output.
Let me know what’s going on.
At what point are you console.logging? If you haven’t instantiated that class, and you aren’t checking that instance, then JS won’t instantiate the class for you. It’s not an object with properties attached until you actually instantiate it.
With the other example, you have an object (the function Rabbit) and you are explicitly adding a speak
property to it’s prototype property.
Also just for future reference can you post code rather than pictures of code? It’s just much easier to check things, can’t copy a picture into the console.
TL;DR
What you expected = Rabbit.prototype.speak
What actually happens = Rabbit.constructor.prototype.speak
To expand on @DanCouper reply you can see speak
in the class as a method assigned to an object that’s why you see no prototype. It’s similar to doing:
Rabbit.speak = function(){ ... }
Another way of seeing it, when you create a function it creates a prototype which has a constructor property and your methods
function Rabbit() { ... }
Rabbit.prototype // will output { constructor: f }
When you use a class your method will be part of the prototype of the constructor, you can check this by checking the instance of the class with weirdRabbit.constructor.prototype.speak
.
And to reinforce Dan, please next time put code instead of just the prints, they help but the code would’ve been great 
1 Like
Thank you for the tip, @DanCouper, and @daspinola. I’ve removed the pictures and replaced them with the code.
In the first example, I’ve added a method explicitly to the prototype of the constructor Rabbit and I get what I expected in the output when console.log
line was executed - Rabbit { speak: [Function] }
In the second example, I get the output - [Function]
.
If both declarations do the same thing, how come I get different outputs for similar inputs?
I’ve fixed my original reply to reflect what I meant of checking the instance and not the declaration.
You want similar outputs you can check this fiddle, execute and see the console, the only difference is that in the class methods like speak
are not enumerable.
You can still question us “Why on pythontutor doesn’t show the same drawing?” and that would be that in the function example you have one declaration of the function “Rabbit” and one expression in the form of Rabbit.prototype.speak = function () { ... }
but for the class you only have the declaration with speak already part of it.
If you want the same drawing in both the function and class declare the class the same as you are declaring the function, meaning with speak
separate from the initial declaration of the class. This also gives speak
enumerable status.
class RabbitClass {
constructor(type) {
this.type = type;
}
}
RabbitClass.prototype.speak = function(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
Notes:
- Fiddle code in case the url stops working for whatever reason
function RabbitFunction(type) {
this.type = type;
}
RabbitFunction.prototype.speak = function(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
};
class RabbitClass {
constructor(type) {
this.type = type;
}
speak(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
}
const weirdRabbitFunction = new RabbitFunction('function')
const weirdRabbitClass = new RabbitClass('class')
console.log('Function declaration ->', RabbitFunction)
console.log('Class declaration ->', RabbitClass)
console.log('Function type ->', typeof RabbitFunction)
console.log('Class type ->', typeof RabbitClass)
console.log('Function prototype ->', RabbitFunction.prototype)
console.log('Class prototype ->', RabbitClass.prototype)
console.log('Function instance ->', weirdRabbitFunction)
console.log('Class instance ->', weirdRabbitClass)
console.log('Function instance prototype ->', weirdRabbitFunction.prototype)
console.log('Class instance prototype ->', weirdRabbitClass.prototype)
console.log('Function instance constructor prototype ->', weirdRabbitFunction.constructor.prototype)
console.log('Class instance constructor prototype ->', weirdRabbitClass.constructor.prototype)
console.log('Function enumerable keys ->', Object.keys(RabbitFunction.prototype))
console.log('Class enumerable keys ->', Object.keys(RabbitClass.prototype))