Classes in JS is syntatic sugar — there are no ‘classes’ like those of class-based programming languages like Java or C++. JS classes do not offer additional functionality, but makes the code for making prototypes and inheritance cleaner.
Previously, we learned how to construct a new object with an object constructor.
function person(first, last){
this.first = first,
this.last = last,
this.fullName = function(){
return this.first + ” ” + this.last;}
}
Under the hood, when you create a new object with an object constructor, it creates copies which include all the constructor’s properties and methods. It could create a waste of storage, for eg: having fullName method copied every single time. Another limitation of the constructor method is that you can’t add new properties to your objects with dot notation:
person1.age = "39"
// returns undefined
To solve this problem, we turn to prototypes.
Prototypes and Inheritance
Every object in JS has an internal object called [[Prototype]]. Whenever you create an object with the object constructor function, by default this [[Prototype]] has a constructor that points back to the function, and a dunder proto __proto__ that points to the [[Prototype]] property of the constructor function.

This prototype object can be used to add new properties and methods to the specific object, like so:
jane.prototype.age= "29";
This works because JavaScript engines first try to find the property on the object; if the property is present on the object it outputs its value. But, if the property is not present on the object then it checks tries to find the property on the prototype object or dunder proto of the object. If the property is found the value is returned else JavaScript engine tries to find the property on the dunder proto of the dunder proto of the object. This chain continues till the dunder proto property is null. In this cases output will be undefined.
This means that when you modify an object A’s property that was a primitive value, other objects will not be affected, as A will create a property on its own object.
//Code from MDN. Let's create an object o from function f with its own properties a and b:
let f = function () {
this.a = 1;
this.b = 2;
}
let o = new f(); // {a: 1, b: 2}
// add properties in f function's prototype
f.prototype.b = 3;
f.prototype.c = 4;
// do not set the prototype f.prototype = {b:3,c:4}; this will break the prototype chain
// o.[[Prototype]] has properties b and c.
// o.[[Prototype]].[[Prototype]] is Object.prototype.
// Finally, o.[[Prototype]].[[Prototype]].[[Prototype]] is null.
// This is the end of the prototype chain, as null,
// by definition, has no [[Prototype]].
// Thus, the full prototype chain looks like:
// {a: 1, b: 2} ---> {b: 3, c: 4} ---> Object.prototype ---> null
console.log(o.a); // 1
// Is there an 'a' own property on o? Yes, and its value is 1.
console.log(o.b); // 2
// Is there a 'b' own property on o? Yes, and its value is 2.
// The prototype also has a 'b' property, but it's not visited.
// This is called Property Shadowing
console.log(o.c); // 4
// Is there a 'c' own property on o? No, check its prototype.
// Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.
console.log(o.d); // undefined
// Is there a 'd' own property on o? No, check its prototype.
// Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
// o.[[Prototype]].[[Prototype]] is Object.prototype and there is no 'd' property by default, check its prototype.
// o.[[Prototype]].[[Prototype]].[[Prototype]] is null, stop searching,
// no property found, return undefined.
Classes
Now that we know classes are just syntactic sugar over constructor functions and prototypes, they are easier to understand:
class person{
constructor(first, last, age) {
this.first = first;
this.last = last;
this.age = age;
}
getName() {
return this.first+ " " + this.last;
}
}
And a new object in the class of person would be created like so:
let person2= new person("Jane", "Doe", 29);
The above code is functionally the same as:
function person(first, last, age) {
this.first = first;
this.last = last;
this.age = age;
}
person.prototype.getName()= function () {
return this.first+ " " + this.last;
}
But there are a few things to note when using ‘class’ to create objects.
- ‘constructor’ requires ‘new’ to work.
- Class methods are non-enumerable.
- If constructor is not declared, a default empty constructor will be added automatically.
- Code inside class is always strict mode.
- Class declarations are not hoisted.
- Class does not allow property value assignment.
- You can use the ‘extends’ keyword to create a child class.
- You can use the ‘super’ keyword to call the constructor of the class it extends from.
class employee extends person{
getName(){
return super.getName()+" is an employee.";
}
}
References:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
https://www.digitalocean.com/community/tutorials/understanding-classes-in-javascript
https://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript
https://www.phpied.com/3-ways-to-define-a-javascript-class/
https://medium.com/tech-tajawal/javascript-classes-under-the-hood-6b26d2667677
https://hackernoon.com/prototypes-in-javascript-5bba2990e04b