What is Object-Oriented Programming
OOP in JavaScript
Constructor Functions and the new Operator
Prototypes
Prototypal Inheritance and The Prototype Chain
ES6 Classes
Setters and Getters
Static Methods
The
Object.create()
Static Method
Inheritance Between "Classes": Constructor Functions
Inheritance Between "Classes": ES6 Classes
Inheritance Between "Classes": Object.create
Public Class Fields and Methods
Encapsulation: Protected Properties and Methods
Encapsulation: Private Class Fields and Methods
Chaining Methods
'use strict';
const Person = function (firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
};
const jonas = new Person('Jonas', 1991);
console.log(jonas);
const matilda = new Person('Matilda', 2017);
const jack = new Person('Jack', 1975);
console.log(matilda, jack);
console.log(jonas instanceof Person);
Person.prototype.calcAge = function () {
console.log(2034 - this.birthYear);
}
jonas.calcAge();
matilda.calcAge();
console.log(jonas.__proto__);
console.log(jonas.__proto__ === Person.prototype);
console.log(Person.prototype.isPrototypeOf(jonas));
console.log(Person.prototype.isPrototypeOf(matilda));
console.log(Person.prototype.isPrototypeOf(Person));
Person.prototype.species = 'Homo Sapiens';
console.log(jonas.species, matilda.species);
console.log(jonas.hasOwnProperty('firstName'));
console.log(jonas.hasOwnProperty('species'));
console.log(Person.prototype);
console.log(jonas.__proto__.__proto__);
console.log(jonas.__proto__.__proto__.__proto__);
console.dir(Person.prototype.constructor);
const arr = [1, 3, 5, 5, 7, 9, 9];
console.log(arr.__proto__);
console.log(arr.__proto__.__proto__);
console.log(arr.__proto__ === Array.prototype);
Array.prototype.uniqueArray = function () {
return [...new Set(this)]
};
console.log(arr.uniqueArray());
console.dir(x => x + 1);
const Car = function (make, speed) {
this.make = make; this.speed = speed;
}
Car.prototype.accelerate = function () {
this.speed += 10;
console.log(`${this.make} is going at ${this.speed} km/h`);
}
Car.prototype.brake = function () {
this.speed -= 5;
console.log(`${this.make} is going at ${this.speed} km/h`);
}
const bmw = new Car('BMW', 120);
const mercedes = new Car('Mercedes', 95);
bmw.accelerate();
bmw.accelerate();
bmw.brake();
bmw.accelerate();
mercedes.accelerate();
mercedes.accelerate();
mercedes.brake();
mercedes.accelerate();
class Persons {
constructor(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
calcAge() {
console.log(2034 - this.birthYear);
}
greet() {
console.log(`Hi, ${this.firstName}.`);
}
}
const jessica = new Persons('Jessica Davis', 1996);
console.log(jessica);
jessica.calcAge();
console.log(jessica.__proto__ === Persons.prototype);
jessica.greet();
const currentYear = new Date().getFullYear();
class PersonGS {
constructor(fullName, birthYear) {
this.fullName = fullName;
this.birthYear = birthYear;
}
get age() { return currentYear - this.birthYear }
get fullName() { return this._fullName; }
set fullName(name) {
if (name.includes(' ')) this._fullName = name;
else console.log(`${name} is not full name.`);
}
}
const tung = new PersonGS('Tung', 1990);
console.log(tung);
console.log(tung.age);
const walter = new PersonGS('Walter White', 1965);
console.log(walter);
console.log(walter.age);
console.log(walter.fullName);
class PersonStatic {
constructor(fullName, birthYear) { this.fullName = fullName; this.birthYear = birthYear; }
get age() { return currentYear - this.birthYear }
get fullName() { return this._fullName; }
set fullName(name) { if (name.includes(' ')) this._fullName = name; else console.log(`${name} is not full name.`); }
static hey() {
console.log('Hey there 👋');
}
}
const me = new PersonStatic('Tung Nguyen', 1990);
PersonStatic.hey();
class PersonStatics {
constructor(fullName, birthYear) { this.fullName = fullName; this.birthYear = birthYear; }
get age() { return currentYear - this.birthYear }
get fullName() { return this._fullName; }
set fullName(name) { if (name.includes(' ')) this._fullName = name; else console.log(`${name} is not full name.`); }
static hey(x) {
console.log(`Hey ${x.fullName} 👋`);
}
}
const mes = new PersonStatics('Tung Nguyen', 1990);
PersonStatics.hey(mes);
const PersonPrototype = {
calcAge() {
console.log(currentYear - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
}
const steven = Object.create(PersonPrototype);
console.log(steven);
steven.name = 'Steven';
steven.birthYear = 2000;
steven.calcAge();
console.log(steven.__proto__ === PersonPrototype);
const sarah = Object.create(PersonPrototype);
sarah.init('Sarah', 1972);
sarah.calcAge();
const person = {
isHuman: false,
printIntroduction: function () {
console.log(`My name is ${this.name}. Am I human? => ${this.isHuman}`);
},
};
const meObj = Object.create(person);
meObj.name = 'Tung';
meObj.isHuman = true;
meObj.printIntroduction();
class Cars {
constructor(make, speed) {
this.make = make;
this.speed = speed;
}
accelerate() {
this.speed += 10;
console.log(`${this.make} is going at ${this.speed} km/h`);
return this;
}
brake() {
this.speed -= 5;
console.log(`${this.make} is going at ${this.speed} km/h`);
return this;
}
get speedUS() { return this.speed / 1.6 }
set speedUS(s) { this.speed = s * 1.6 }
}
const ford = new Cars('Ford', 120);
ford.accelerate();
ford.accelerate();
ford.brake();
ford.speedUS = 50;
console.log(ford.speed);
const ThePerson = function (firstName, birthYear) {
this.firstName = firstName; this.birthYear = birthYear;
}
ThePerson.prototype.calcAge = function () { console.log(currentYear - this.birthYear) };
const TheStudent = function (firstName, birthYear, course) {
ThePerson.call(this, firstName, birthYear); this.course = course;
}
TheStudent.prototype = Object.create(ThePerson.prototype);
TheStudent.prototype.introduce = function () { console.log(`My name is ${this.firstName}, and I study ${this.course}.`) };
const mike = new TheStudent('Mike', 2000, 'Computer Science');
mike.introduce();
mike.calcAge();
console.log(mike.__proto__);
console.log(mike.__proto__.__proto__);
TheStudent.prototype.constructor = TheStudent;
console.dir(TheStudent.prototype.constructor);
console.log(mike instanceof TheStudent);
console.log(mike instanceof ThePerson);
console.log(mike instanceof Object);
const EV = function (make, speed, charge) {
Car.call(this, make, speed);
this.charge = charge;
}
EV.prototype = Object.create(Car.prototype);
EV.prototype.chargeBattery = function (chargeTo) { this.charge = chargeTo };
EV.prototype.accelerate = function () {
this.speed += 20; this.charge--;
console.log(`${this.make} is going at ${this.speed} km/h, with a charge of ${this.charge}%`);
}
const tesla = new EV('Tesla', 120, 23);
tesla.chargeBattery(90);
tesla.brake();
tesla.accelerate();
class ThePersons {
constructor(fullName, birthYear) { this._fullName = fullName; this.birthYear = birthYear; }
get age() { return currentYear - this.birthYear }
get fullName() { return this._fullName; }
set fullName(name) { if (name.includes(' ')) this._fullName = name; else console.log(`${name} is not full name.`); }
calcAge() { console.log(this.age) }
static hey() {
console.log('Hey there 👋');
}
}
class TheStudents extends ThePersons {
constructor(fullName, birthYear, course) {
super(fullName, birthYear);
this.course = course;
}
introduce() { console.log(`My name is ${this.fullName}, and I study ${this.course}.`) };
calcAge() {
console.log(
`I'm ${this.age} years old, but as a student I feel more like ${this.age + 5}.`
);
}
}
const martha = new TheStudents('Martha Jones', 2002, 'Computer Science');
martha.introduce();
martha.calcAge();
const ThePersonPrototype = {
calcAge() {
console.log(currentYear - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
}
const stevens = Object.create(ThePersonPrototype);
const TheStudentPrototype = Object.create(ThePersonPrototype);
TheStudentPrototype.init = function (firstName, birthYear, course) {
ThePersonPrototype.init.call(this, firstName, birthYear);
this.course = course;
}
TheStudentPrototype.introduce = function () { console.log(`My name is ${this.firstName}, and I study ${this.course}.`) };
const jay = Object.create(TheStudentPrototype);
jay.init('Jay', 2000, 'Computer Science');
jay.introduce();
jay.calcAge();
class Account {
constructor(owner, currency, pin) {
this.owner = owner;
this.currency = currency;
this.pin = pin;
this.movements = [];
this.locale = navigator.language;
console.log(`Thanks for opening an account, ${owner}.`);
}
deposit(val) { this.movements.push(val) }
withdraw(val) { this.deposit(-val) }
approveLoan() { return true }
requestLoan(val) { if (this.approveLoan()) { this.deposit(val); console.log('Loan approved.') } }
}
const tungAcc = new Account('Tung', 'VND', 1234);
tungAcc.deposit(250);
tungAcc.withdraw(140);
tungAcc.requestLoan(1000);
console.log(tungAcc);
class AccountProtect {
constructor(owner, currency, pin) {
this.owner = owner;
this.currency = currency;
this.locale = navigator.language;
console.log(`Thanks for opening an account, ${owner}.`);
this._pin = pin;
this._movements = [];
}
_approveLoan() { return true }
getMovements() { return this._movements }
deposit(val) { this._movements.push(val) }
withdraw(val) { this.deposit(-val) }
requestLoan(val) { if (this._approveLoan()) { this.deposit(val); console.log('Loan approved.') } }
}
const tungOne = new AccountProtect('Tung', 'VND', 1234);
tungOne.deposit(250);
tungOne.withdraw(140);
tungOne.requestLoan(1000);
class AccountPrivate {
locale = navigator.language;
#pin;
#movements = [];
constructor(owner, currency, pin) {
this.#pin = pin;
this.owner = owner;
this.currency = currency;
console.log(`Thanks for opening an account, ${owner}.`);
}
#approveLoan() { return true }
getMovements() { return this.#movements }
deposit(val) { this.#movements.push(val); return this; }
withdraw(val) { this.deposit(-val); return this; }
requestLoan(val) { if (this.#approveLoan()) { this.deposit(val); console.log('Loan approved.'); return this; } }
}
const tungTwo = new AccountPrivate('Tung', 'VND', 1234);
tungTwo.deposit(250);
tungTwo.withdraw(140);
tungTwo.requestLoan(1000);
console.log(tungTwo);
console.log(tungTwo.movements);
console.log(tungTwo.pin)
tungTwo.deposit(300).deposit(500).withdraw(350).requestLoan(20000).withdraw(4000);
console.log(tungTwo.getMovements());
class EVs extends Cars {
#charge;
constructor(make, speed, charge) {
super(make, speed);
this.#charge = charge;
}
chargeBattery(chargeTo) {
this.#charge = chargeTo;
return this;
};
accelerate() {
this.speed += 20;
this.#charge--;
console.log(`${this.make} is going at ${this.speed} km/h, with a charge of ${this.#charge}%`);
return this;
}
}
const rivian = new EVs('Rivian', 120, 23);
console.log(rivian);
rivian.accelerate().accelerate().accelerate().brake().chargeBattery(51).accelerate();
console.log(rivian.speedUS);