Основы ООП JS: подробно для всех
Объектно-ориентированное программирование – это популярный на сегодняшний день способ создания программных продуктов. Его миссия – упростить написание, чтение и работу с кодом. Эту парадигму поддерживают множество языков: C#, C++, Cyclone, Groovy, Io, Java, Objective-C, Perl, PHP, Python, Ruby, Scala и другие. Ну а как же насчет JavaScript? Хотя он также относится к объектно-ориентированным языкам, программирование ООП в JS происходит по-другому, со своими особенностями. В этой статье мы разберем, что такое ООП JS, как реализуются принципы парадигмы в этом языке и чем отличается процесс разработки.
Парадигма ООП JS
Прежде чем приступить к разбору JavaScript ООП, для начинающих стоит напомнить, что из себя представляет объектно-ориентированное программирование.
Простыми словами, это шаблон написания программы, в котором для решения поставленных задач используются объекты со своими свойствами (характеристиками) и методами (поведением). Как правило, в объектно-ориентированных языках эта парадигма реализуется на основе классов. Сначала создается класс, в котором заданы свойства и методы будущих экземпляров, а потом уже в нем производятся сами объекты.
Реализация ООП на JS происходит через прототипы (функции-конструкторы). По этой причине многие эксперты считают JavaScript не самым объектно-ориентированным языком. Ведь по сути объектом считается всё в JS (классы ООП в том числе). Поэтому прототипирование – оптимальный способ добиться решения задач на ООП JS. Таким образом, JavaScript больше подходит название «прототипно-ориентированный».
Объектно-ориентированное программирование строится на четырех основных принципах:
- наследование;
- инкапсуляция;
- абстракция;
- полиморфизм.
Из-за особенностей JavaScript реализация этих принципов также отличается.
Принципы ООП JS
Подробное описание сути принципов объектно-ориентированного программирования есть в другой нашей статье, так что не будем повторяться и поговорим конкретно об ООП принципах в JS.
Начнем с основного различия – наследование. В классическом варианте классы-потомки наследуют свойства и методы класса-родителя, дополняя их своими характеристиками по необходимости.
Так как в прототипном наследовании классов нет, этот принцип ООП JS реализуется через создание одного объекта из другого. Для этого создается обобщенный прототип, а уже из него производятся клоны (экземпляры) с расширенными функциями. Плюс такого наследования – в динамичности: вслед за изменением в родителе идет трансформация в потомках, чем не может похвастаться классическая схема.
Что интересно, в ООП JS ES6, появилась реализация, приближенная к стандартной: создание родителя через class. Тем не менее то, что мы получаем, не считается традиционным классом, а служит лишь синтаксическим сахаром. То есть мы все равно продолжаем работать с функциями-конструкторами. По этой причине также некоторые характеризуют рассматриваемую парадигму в JavaScript как «JS ООП в функциональном стиле».
Теперь перейдем к инкапсуляции. Модификаторов доступа private, public и protected в языке нет за счет отсутствия классов. Ранее по договоренности для объявления приватности добавлялось нижнее подчеркивание «_». Но это решение считалось весьма спорным.
Чтобы соблюдение этого ООП принципа JS стало возможным, для организации инкапсуляции здесь используются замыкания.
Они не делают данные невидимыми, так как по сути любой код в JavaScript можно вытащить из браузера. Но к этим данным нельзя обратиться напрямую, получить и, соответственно, изменить.
Абстракция ООП JS – это принцип, который подразумевает создание важных для программы свойств и методов, но абстрагируются они не в классе, а в прототипе (конструкторе). Всё, что не важно для достижения цели, скрывается, остаются только существенные детали.

Полиморфизм в предполагает следующее: методы родительского объекта (прототипа) наследуются дочерними, но реализация этих методов в зависимости от свойств того или иного объекта будет отличаться. Чтобы объяснить полиморфизм в JavaScript ООП для начинающих, приведем простой пример. Допустим, наш прототип (конструктор) – животное. У него есть описанные свойства (отряд, размер, место обитания и пр.), а также методы (плавает, летает, издает звуки). Возьмем последний метод – воспроизведение звуков: реакция кошки на него будет одна, а собаки – другая. То есть метод один и тот же, а реализация разная.
Ну что ж, давайте рассмотрим теперь ООП JS на примерах.

JavaScript ООП. Примеры
Итак, мы уже обсудили момент, что вместо классов в JavaScript используются прототипы (конструкторы).
Они как раз и дают абстрактное описание, шаблон будущих объектов.
Правила создания функции-конструктора:
- Имя с заглавной буквы.
- Вызов функции – через оператора new.
В работе с конструкторами и объектами используется ключевое слово this. Его значение зависит от контекста применения. С помощью this мы обращаемся к чему-либо.
Приведем по ООП JS примеры. Создадим конструктор Person, определим его свойства и методы, а затем добавим новый объект:
console.log('*** PERSON ***');
function Person (name) {
this.name = name;
}
Person.prototype = {
eyes: 2,
mouth: 1,
sleep: function () {
return 'zzz';
}
};
// создание человека (Person)
const p1 = new Person('John');
// прописываем:
console.log(
`name: ${p1.name}`,
`eyes: ${p1.eyes}`,
`mouth: ${p1.mouth}`,
p1.sleep()
);
Чтобы создать на основе «класса» конструктор Employee, наследуем его свойства и добавим нужные характеристики (заработная плата), убрав лишние:
function Employee (name, salary) {
this.name = name;
this.salary = salary;
}
// Прототип наследования
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee; // Устанавливаем его конструктор
// Повторяем то же самое
// Создаем сотрудника
const em1 = new Employee('Jack', 2500);
// и прописываем:
console.log(
`name: ${em1.name}`,
`salary: ${em1.salary} USD`,
`eyes: ${em1.eyes}`,
`mouth: ${em1.mouth}`,
em1.sleep()
);
В ES6 создание конструктора происходит через class, а наследование будет выглядеть проще:
class Employee extends Person {
constructor (name, salary) {
super(name);
this.salary = salary;
}
}
В этой статье мы кратко рассмотрели, что из себя представляет ООП в JS. Как вы поняли, с языком JavaScript объектно-ориентированное программирование работает по-другому, через прототипы. Эта методика более простая и гибкая, ведь в таком случае вы сможете создавать столько объектов, сколько нужно, прикрепляя данные и функции по мере необходимости.
Однако быстро освоить процесс создания ОО-программ на JavaScript после изучения этой парадигмы в классическом исполнении вряд ли получится. Понять лучше особенности языка вам помогут видеоматериалы, а также книги.
Из новинок:
- Megane Noel «JavaScript for Beginners: A Complete Guide to Learn the Fundamentals of JavaScript and Start Programming Today!» (вторая книга из серии «Computer Programming», ноябрь, 2021).
- David Flanagan «JavaScript: The Definitive Guide: Master the World’s Most-Used Programming Language» (июнь, 2020).
- Cay Horstmann «Modern JavaScript for the Impatient» (июль, 2020).
- Adam D. Scott , Matthew MacDonald «JavaScript Cookbook: Programming the Web» (август, 2021).
- Rob Miles «Begin to Code with JavaScript» (август, 2021).
Также рекомендуем книгу автора Douglas Crockford «How JavaScript Works», которая есть и на русском языке (Дуглас Крокфорд «Как устроен JavaScript»). Выпущена она еще в 2018 году, но именно здесь автор уделяет много внимания вопросу: почему парадигма реализована в этом языке именно так. Методы взаимодействия JavaScript с объектно-ориентированным программированием подробно описаны к работе авторов Ved Antani и Stoyan Stefanov «Object-Oriented JavaScript: Learn everything you need to know about object-oriented JavaScript» (3-е издание, январь, 2017).
Да, JavaScript является ООП языком. Но принцип реализации этой парадигмы на JS несколько иной. В основе объектно-ориентированного программирования лежат классы и объекты. Но объектами в JavaScript считается всё, поэтому создать шаблон (класс) не получится, ведь он тоже станет объектом. Поэтому ООП в JS основывается не на классовом, а на прототипном наследовании. Создается обобщенный объект-родитель, где прописываются нужные свойства и методы, а уже от него производятся другие объекты.
Объект – самостоятельная единица, которая состоит из методов и свойств. Каждый из них содержит имя и значение. Свойства – это характеристики объекта, а методы – поведение. Объект – основной вид данных в языке JS. Любое значение в JavaScript (если это не строка, число или логическое значение) – это объект. Но даже то, что указано в скобках, может вести себя как неизменяемые объекты. Исходя из этой особенности ООП основывается в JS не на классах, а на прототипах. Чтобы создать ряд объектов, используется конструктор – обобщенный объект, где прописаны основные свойства для потомков.
Да, объектно-ориентированное программирование важно в JavaScript. Когда вы разрабатываете небольшую программу самостоятельно, то применять ООП не имеет никакого смысла. Но если это крупный проект, то использование этой парадигмы решит ряд проблем: поддерживать, изменять и расширять существующий код будет гораздо проще. Благодаря прототипному наследованию, которое считается особенностью JS ООП, программирование становится более динамичным и гибким. Это особенно важно, когда над программой работает группа разработчиков.
Существует два способа создать объект в JavaScript.
Первый способ:
var obj = new Object({'name':'Alex'});
Это объект с одним свойством name, которое имеет значение «Alex».
Второй (сокращенный) способ:
var obj = {'name':'Alex'};
Если необходимо указать несколько свойств, между ними ставятся разделители – запятые:
var obj = {
'name': 'Alex',
'lastname': 'Ivanov'
};
Объект в JavaScript – это набор данных и функциональных возможностей. Как правило, он состоит из нескольких переменных и функций (свойств и методов). Свойства – это характеристики, а методы – поведение (что он умеет делать).
Класса как такового не существует в JS, так как ключевой тип данных здесь – объекты. Вместо него используются прототипы – обобщенные объекты с прописанными функциями, на основании которых создаются новые экземпляры (потомки).
В JavaScript ES6 появилась реализация, похожая внешне на классовую: родитель создается через class. Однако это лишь синтаксический сахар. По сути программист все равно продолжает работать с прототипами, которые реализуются через функции-конструкторы.