OOP in JavaScript & some differences from the other languages
» About
JavaScript is the most widely used language on the web but is also used for desktop (Electron.js) and mobile (React Native, Cordova, etc.) apps. In this a bit shorter blog, I will try to explain the best way possible OOP in JavaScript. I will specifically explain the main differences from the other OOP languages like Java or C# and also give a few examples, which may help you if you are new to JS, but already have some experience in other languages.
» Outline
- About
- Prototype (based) language
- Some keywords
- Classic syntax vs ES6 syntax
- Dynamic typing
- Public & Private fields
- Conclusion
» Prototype (based) language
Unlike the usual OOP languages, JavaScript is prototype-based, which means that the objects inherit the data from prototypes. But what is a prototype exactly?
Imagine you have cookies like from the popular TV Show Squid Game:
Then we take the O cookie and create 4 multiples of them through a cutter machine that cuts them perfectly, and every one of them is totally identical. Now imagine on that machine you change the shape, and magically all the cookies you previously cut change the shape too; in this case, the “machine” is the prototype in JavaScript.
// Machine changes the shape
Cookie.prototype.shape = "star";
Let’s now give it technically a go; a prototype is just a hidden parent object that teaches new objects what “they don’t know”. When you create a class, JavaScript automatically creates a hidden object called a prototype. The prototype acts like a shared parent for all objects (instances) created from the class. If an object doesn’t know something, it looks up to its prototype to see if it can find it there. Take this technical example:
class Car {
constructor(name) {
this.name = name;
}
}
const audi = new Car("A3");
const bmw = new Car("M3");
Car.prototype.fuel = "Diesel";
Some keywords
prototype
We already used one keyword above, and that’s the prototype
, it’s the prototype a.k.a. the property under every object that represents the parent object.
class Car {}
console.log(Car.prototype); // { constructor: class Car() [[Prototype]]: Object }
constructor
This is a property of the prototype that will point back to the class the prototype was created from. Like every OOP language, JS has constructor()
too, but don’t get it mixed up with the constructor
, this is the property of the prototype, not the object’s function call when the object is created from the class itself.
class Car {}
console.log(Car.prototype.constructor); // class Car {}
__proto__
This is the internal reference which points to the object prototype
, this has been deprecated in the modern browsers, now there are more modern approaches for Get/Set like Object.getPrototypeOf()
or Object.setPrototypeOf()
.
instanceof
instanceof
checks if an object was created from a specific class and returns a boolean type.
class Car {}
const audi = new Car();
console.log(audi instanceof Car); // true
Classic syntax vs ES6 syntax
For our examples, we used the classic class
syntax, but that wasn’t available in the pure JS before the ES6 update. Functions, arrays, and pretty much everything in JavaScript that is not a default primitive type like numbers or strings is an object. This is how we would create the Car
class and audi
object from the example above:
function Car(name) {
this.name = name;
}
// You would also have to add methods through the prototypes
Car.prototype.go = function() {
console.log("vrrr");
};
const audi = new Car("A3");
With the update of EcmaScript in 2015, the class
syntax was implemented with no need anymore to use the functions.
class Car {
constructor(name) {
this.name = name;
}
go() {
console.log("vrrr");
}
}
Dynamic typing
Properties in JavaScript are dynamically typed, which means you won’t have to specify a type for the property. JS does it automatically for you. Take this example in Java:
class Car {
private String name;
private int price;
public Car(String name, int price) {
this.name = name;
this.price = price;
}
}
Car audi = new Car("A5", 13000);
Notice the types above (name
- String and price
- Integer).
In JS it would be like this:
class Car {
constructor(name, price) {
this.name = name;
this.price = price;
}
}
let audi = new Car("A5", 13000);
audi.name = "A6";
audi.price = 15000;
Also later if you want to change for example the audi.name
to an integer like this:
audi.name = 123;
This would not cause any errors normally, because there is no type safety in JavaScript, unlike other languages like Java.
Public & Private fields
By default the fields in JavaScript are public; if you want to make them inaccessible from outside the class, you need to add the # prefix before the field to make them private. Take this for example:
class Car {
#name; // Private field
#price; // Private field
constructor(name, price) {
this.#name = name;
this.#price = price;
}
}
let audi = new Car("A5", 13000);
console.log(audi.#price); // Syntax error
audi.#name = "A4"; // Syntax error
You can also create private methods by adding the # prefix. Since JavaScript was not by default designed to be an OOP language, there is no protected
keyword.