JavaScript не є об'єктно-орієнтованою мовою на основі класів. Але він все ще має способи використання об’єктно-орієнтованого програмування (ООП).
У цьому посібнику я розтлумачу ООП та покажу вам, як ним користуватися.
Відповідно до Вікіпедії, програмування на основі класів є
стиль об’єктно-орієнтованого програмування (ООП), в якому успадкування відбувається за допомогою визначення класів об’єктів, замість успадкування, що відбувається лише за допомогою об’єктів
Найпопулярніша модель ООП - це класова.
Але, як я вже згадував, JavaScript не є класифікованою мовою - це прототип.
Згідно з документальним фільмом Mozilla:
Мова, заснована на прототипі, має поняття прототипового об'єкта, об'єкта, що використовується як шаблон, з якого можна отримати початкові властивості нового об'єкта.
Погляньте на цей код:
let names = { fname: "Dillion", lname: "Megida" } console.log(names.fname); console.log(names.hasOwnProperty("mname")); // Expected Output // Dillion // false
Змінна об’єкта names
має лише дві властивості - fname
і lname
. Ніяких методів взагалі.
То звідки береться hasOwnProperty
?
Ну, це походить від Object
прототипу.
Спробуйте записати вміст змінної на консоль:
console.log(names);
Коли ви розгорнете результати в консолі, ви отримаєте таке:

Зверніть увагу на останню властивість - __proto__
? Спробуйте розширити його:

Ви побачите набір властивостей під Object
конструктором. Всі ці властивості походять від глобального Object
прототипу. Якщо ви уважно подивитеся, ви також помітите , наш прихований hasOwnProperty
.
Іншими словами, усі об'єкти мають доступ до Object
прототипу '. Вони не володіють цими властивостями, але їм надається доступ до властивостей у прототипі.
__proto__
нерухомість
Це вказує на об’єкт, який використовується як прототип.
Це властивість кожного об’єкта, що надає йому доступ до Object prototype
властивості.
Кожен об'єкт має цю властивість за замовчуванням, яка посилається на за Object Protoype
винятком випадків, коли налаштовано інакше (тобто коли об'єкт __proto__
вказує на інший прототип).
Змінення __proto__
властивості
Цю властивість можна змінити, прямо вказавши, що вона повинна посилатися на інший прототип. Для досягнення цього використовуються такі методи:
Object.create()
function DogObject(name, age) { let dog = Object.create(constructorObject); dog.name = name; dog.age = age; return dog; } let constructorObject = { speak: function(){ return "I am a dog" } } let bingo = DogObject("Bingo", 54); console.log(bingo);
У консолі це те, що у вас буде:

Помітили __proto__
властивість і speak
спосіб?
Object.create
використовує аргумент, переданий йому, щоб стати прототипом.
new
ключове слово
function DogObject(name, age) { this.name = name; this.age = age; } DogObject.prototype.speak = function() { return "I am a dog"; } let john = new DogObject("John", 45);
john
__proto__
властивість ' спрямовано на DogObject
прототип'. Але пам’ятайте, DogObject
прототип Росії - це об’єкт ( пара ключ і значення ), отже, він також має __proto__
властивість, що посилається на глобальний Object
прототип.
Ця техніка називається ЛАНЦЮГОМ ПРОТОПИПУ .
Зверніть увагу:new
підхід до ключових слів робить те саме, що Object.create()
робить, але лише полегшує, оскільки робить деякі речі автоматично для вас.
І так ...
Кожен об'єкт у Javascript має доступ до Object
прототипу '' за замовчуванням. Скажімо prototype2
, якщо налаштовано використовувати інший прототип, він prototype2
також матиме доступ до прототипу Об’єкта за замовчуванням тощо.
Об'єкт + комбінація функцій
Вас, мабуть, бентежить той факт, що DogObject
це функція ( function DogObject(){}
), і вона має властивості, доступні за допомогою крапкового позначення . Це називається комбінацією функціональних об'єктів .
Коли функції оголошуються, за замовчуванням їм надається багато властивостей, приєднаних до нього. Пам'ятайте, що функції також є об'єктами в типах даних JavaScript.
Тепер, Клас
JavaScript ввів class
ключове слово в ECMAScript 2015. Це робить JavaScript схожим на мову ООП. Але це лише синтатичний цукор у порівнянні з існуючою технікою прототипування. Він продовжує створювати прототипи у фоновому режимі, але робить зовнішній корпус схожим на ООП. Зараз ми розглянемо, як це можливо.
Наступний приклад - загальне використання a class
у JavaScript:
class Animals { constructor(name, specie) { this.name = name; this.specie = specie; } sing() { return `${this.name} can sing`; } dance() { return `${this.name} can dance`; } } let bingo = new Animals("Bingo", "Hairy"); console.log(bingo);
Ось результат у консолі:

The __proto__
references the Animals
prototype (which in turn references the Object
prototype).
From this, we can see that the constructor defines the major features while everything outside the constructor (sing()
and dance()
) are the bonus features (prototypes).
In the background, using the new
keyword approach, the above translates to:
function Animals(name, specie) { this.name = name; this.specie = specie; } Animals.prototype.sing = function(){ return `${this.name} can sing`; } Animals.prototype.dance = function() { return `${this.name} can dance`; } let Bingo = new Animals("Bingo", "Hairy");
Subclassing
This is a feature in OOP where a class inherits features from a parent class but possesses extra features which the parent doesn't.
The idea here is, for example, say you want to create a cats class. Instead of creating the class from scratch - stating the name, age and species property afresh, you'd inherit those properties from the parent animals class.
This cats class can then have extra properties like color of whiskers.
Let's see how subclasses are done with class
.
Here, we need a parent which the subclass inherits from. Examine the following code:
class Animals { constructor(name, age) { this.name = name; this.age = age; } sing() { return `${this.name} can sing`; } dance() { return `${this.name} can dance`; } } class Cats extends Animals { constructor(name, age, whiskerColor) { super(name, age); this.whiskerColor = whiskerColor; } whiskers() { return `I have ${this.whiskerColor} whiskers`; } } let clara = new Cats("Clara", 33, "indigo");
With the above, we get the following outputs:
console.log(clara.sing()); console.log(clara.whiskers()); // Expected Output // "Clara can sing" // "I have indigo whiskers"
When you log the contents of clara out in the console, we have:

You'll notice that clara
has a __proto__
property which references the constructor Cats
and gets access to the whiskers()
method. This __proto__
property also has a __proto__
property which references the constructor Animals
thereby getting access to sing()
and dance()
. name
and age
are properties that exist on every object created from this.
Using the Object.create
method approach, the above translates to:
function Animals(name, age) { let newAnimal = Object.create(animalConstructor); newAnimal.name = name; newAnimal.age = age; return newAnimal; } let animalConstructor = { sing: function() { return `${this.name} can sing`; }, dance: function() { return `${this.name} can dance`; } } function Cats(name, age, whiskerColor) { let newCat = Animals(name, age); Object.setPrototypeOf(newCat, catConstructor); newCat.whiskerColor = whiskerColor; return newCat; } let catConstructor = { whiskers() { return `I have ${this.whiskerColor} whiskers`; } } Object.setPrototypeOf(catConstructor, animalConstructor); const clara = Cats("Clara", 33, "purple"); clara.sing(); clara.whiskers(); // Expected Output // "Clara can sing" // "I have purple whiskers"
Object.setPrototypeOf
is a method which takes in two arguments - the object (first argument) and the desired prototype (second argument).
From the above, the Animals
function returns an object with the animalConstructor
as prototype. The Cats
function returns an object with catConstructor
as it's prototype. catConstructor
on the other hand, is given a prototype of animalConstructor
.
Therefore, ordinary animals only have access to the animalConstructor
but cats have access to the catConstructor
and the animalConstructor
.
Wrapping Up
JavaScript leverages its prototype nature to welcome OOP developers to its ecosystem. It also provides easy ways to creating prototypes and organize related data.
True OOP languages do not perform prototyping in the background - just take note of that.
A big thanks to Will Sentance's course on Frontend Masters - JavaScript: The Hard Parts of Object Oriented JavaScript. I learned everything you see in this article (plus a little extra research) from his course. You should check it out.
You can hit me up on Twitter at iamdillion for any questions or contributions.
Thanks for reading : )
Useful Resources
- Object-oriented JavaScript for beginners
- Introduction to Object Oriented Programming in JavaScript