Javascript : OOP
Fifth article on my javascript exploration and I explain here the differences between javascript and and other regular Object Oriented Programming languages. ES6 made it easier but it is important to understand how inheritance is adressed in js.
Prototype
Javascript is a prototype-based OOP. Unlike other programming languages, classes do not exist in javascript (even the class
keyword introduced further below is not a class per say). Instead, everything is an object.
In JS, all functions include a prototype
object by default, which is a special type of enumerable object to which properties can be attached. These properties will be shared across all the instances of its constructor function.
// This is the legacy way of creating 'classes' in javascript
function Person() {
// The body of this function is called the 'constructor function'.
// 'this' is valid in a function. It adds the following properties to
// the 'prototype' of the object and they'll be shared with all instances
this.name = 'Mike';
this.gender = 'Male';
}
// You can add new properties to 'Person'
Person.prototype.age = 41;
// Internally, 'mike' has a `__proto__` property that points to the 'prototype' object
// of 'Person'. Note that instances, do not have the 'prototype' property (it is invisible).
var mike = new Person();
console.log(mike.age); // 41
// To access 'prototype' from an instance, use the following
let proto = Object.getPrototypeOf(mike); // returns 'Person's prototype object
// 'prototype' has a property named 'constructor' which points to Person() method
console.log(proto.constructor);
Any change made to the prototype
only reflects in new instances. Old instances keep a reference to the old prototype
.
var mike = new Person();
Person.prototype = { name: 'Jody', gender: 'Female' };
var jody = new Person();
console.log(mike.name); // 'Mike'
console.log(jody.name); // 'Jody'
You can attach new functions and properties to an instance (this is how javascript handles inheritance). Then when calling a function or property, the javascript engine looks it up into the prototype
of the instance first and escalates to parents' prototype
until finding it.
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
// we create an 'Employee' class
// inheriting 'Person'
function Employee(name, gender, position) {
// call Person's constructor in this context
Person.call(this, name, gender);
this.position = position;
}
// build inheritance
Employee.prototype = new Person();
Employee.prototype.constructor = Person;
let employee = new Employee('Mark', 'Male', 'Architect');
console.log(employee instanceof Person); // true
console.log(employee instanceof Employee); // true
Classes
Introduced with ES6, class
is a syntactic sugar to easily write object-oriented code similarly to other OOP languages, but in the background, javascript still uses the prototype-based inheritance.
class Car {
// Constructor
constructor(name, year) {
this.name = name; // this. auto creates a property
this.year = year;
}
// Method
age() {
const date = new Date();
return date.getFullYear() - this.year;
}
}
Note that a class or its methods can be marked as static
.
Inheritance
class Model extends Car {
constructor(brand, mod) {
super(brand); // super() lets you call parent class
this.model = mod;
}
// Polymorphism is as simple as redefining parent method
age() {
return 1;
}
show() {
return this.present() + ', it is a ' + this.model;
}
}
Getters/Setter
Syntactically getters and setters are like special functions:
class Car {
// Constructor
constructor(name, year) {
this.name = name; // this. auto creates a property
this.year = year;
}
get carname() {
return this.name;
}
set carname(x) {
this.name = x;
}
}
const myCar = new Car("BMW", 2022);
console.log(myCar.carname);
Visibility
Note that visibility attributes do not exist in javascript. There is no public
, protected
or private
qualifiers here.