JavaScript может быть не тем, что приходит в голову, когда кто-то упоминает язык ООП, но факт в том, что он имеет отличную поддержку ООП - в нем просто есть свои сложности, которые необходимо сначала понять.

Если вы пишете код на JavaScript, знакомство с принципами ООП может облегчить вам жизнь по нескольким причинам:

  • При использовании объектов и классов легче отлаживать код.
  • Вы можете использовать такие методы, как инкапсуляция и наследование.
  • Вам будет легче попасть в команду, использующую принципы ООП для своего кода.

Здесь вы познакомитесь с основами объектно-ориентированного JavaScript в ES5 и ES6, чтобы увидеть сравнения и то, как JavaScript перешел к стилю ООП. Во-первых, в этом посте рассматривается ООП в ES5 и основы, которые вам необходимо знать, такие как объекты, функции конструктора и синтаксис, связанный с доступом к свойствам объекта.

Ближе к задней части поста будет рассмотрен ООП в ES6 и использование классов, свойств прототипов и методов.

Что такое ООП (объектно-ориентированное программирование)?

Если вы знакомы с другими языками, такими как C # и Java, то, вероятно, слышали термин объектно-ориентированное программирование (ООП).

Объектно-ориентированное программирование - это стиль программирования, а не инструмент, поэтому, несмотря на то, что это старый стиль, он все еще очень популярен и широко используется. Этот стиль предполагает разбиение программы на сегменты объектов, которые могут взаимодействовать друг с другом. Каждый объект определяется своим собственным набором свойств, к которым затем можно получить доступ и изменить с помощью различных операций.

Приведенная выше иллюстрация представляет собой реальный пример записи о сотруднике, где каждый сотрудник может считаться «объектом», а поскольку у каждого сотрудника есть имя, возраст и должность, они могут считаться свойствами этого сотрудника.

ООП в JavaScript (ES5)

ООП в JavaScript работает иначе, чем в других языках. Итак, если вы знакомы с ООП на других языках, важно, чтобы вы отложили эти знания в сторону, так как использование этих концепций может вас смутить.

Вы, наверное, видели, что другие языки, такие как C ++, Java и C #, используют ключевое слово class для определения класса. В классе есть свойства и методы для каждого экземпляра этого класса. В этом случае класс действует как образец для объекта.

JavaScript отличается от других языков, потому что вы можете реализовать ООП без использования классов (подробнее об этом позже). До выпуска версии ES2015 JavaScript все еще полагался на программирование на основе прототипов. В этом стиле программирования объект инкапсулирует свойства, то есть его методы и данные, а не класс. Вы можете добавить к этому объекту новые свойства в любое время. Итак, теперь объект может быть индивидуальным, а не экземпляром класса, то есть, если вам нужен объект, вы легко можете просто создать его, не создавая сначала класс.

ООП на основе прототипов и классов имеют свои преимущества и недостатки.

На основе прототипа проще, поскольку вам не нужно заранее создавать план, который требует предварительного планирования в отношении того, какие свойства требуются перед созданием объекта.

Поскольку создавать классы не требуется, вы можете создать объект напрямую. Это также обеспечивает гибкость; следовательно, любые изменения объектов можно легко и быстро внести во время их использования.

Хотя все эти преимущества существуют в программировании на основе прототипов, существует более высокий риск ошибки, поскольку можно легко внести резкие изменения. В то время как в подходе, основанном на классах, чертежи заранее составляют план, что снижает вероятность возникновения ошибок.

Объекты в JavaScript

Объекты - это основная часть JavaScript, поскольку почти все в нем является объектами. Например, функции, массивы, регулярные выражения, даты и даже типы данных, такие как логические и строковые, если они объявлены с ключевым словом new, могут считаться объектом javascript.

Что такое объект

В реальной жизни объекты можно найти повсюду, поэтому эти реальные сценарии также могут быть отображены в объектно-ориентированном коде.

Давайте посмотрим на пример того, как используются объекты:
Предположим, у вас есть три формы, площадь которых вам нужно найти: квадрат, прямоугольник и круг.

Если бы вам пришлось написать код, который вычислял бы площадь каждого, что бы вы сделали?

В стиле ООП вы преобразовываете код, создавая объекты для каждой формы: квадрата, прямоугольника и круга. Здесь каждый объект имеет свой собственный набор свойств, который включает:

Нам нужны длина, ширина и радиус. Эти значения будут заключены в объект этой конкретной формы.

Точно так же потребуется функция для расчета площади. Это также будет инкапсулировано в объект как часть его свойств.

Как создать литерал объекта

Литерал объекта может быть создан:

  • используя фигурные скобки {...} в объявлении.
  • используя ключевое слово new.
  • на основе существующего объекта с использованием метода create().

Все эти подходы делают одно и то же.

Вот как выглядит синтаксис:

Использование фигурных скобок

var objectName = {
//properties defined 
  propertyName1 : propertyValue1, 
  propertyName2 : propertyValue2, 
  functionName() {} 
}

Использование ключевого слова new

var objectName = new Object()

Использование метода create()

var newObjectName = Object.create(existingObjectName)

Доступ к свойствам объекта

Есть разные способы доступа к свойствам объекта. Выделены несколько популярных способов, но вы также можете перебирать свойства объекта, используя цикл for..in, и вы также можете получить доступ к свойствам вложенного цикла (для реализации этого все, что требуется, - это использовать оператор точки, но вам понадобится чтобы добавить еще одну точку).

Оператор точки (также полезен для установки и удаления свойств)
В JavaScript к литералу объекта можно получить доступ с помощью оператора точки. Чтобы получить доступ к какому-либо свойству, сначала следует упомянуть имя объекта, затем оператор точки, а затем имя свойства, инкапсулированного в этом объекте.

Здесь мы можем увидеть синтаксис оператора точки:

objectName.functionName()

Вот пример того, как получить доступ к свойствам с помощью оператора точки:

//creating an object named shape
var shape = {
//defining properties of the object 
  //setting data values 
  name : 'square', sides : 4 
}
//accessing the properties using the dot operator 
console.log("Name is:", shape.name) //using dot operator to access "name"
console.log("Number of sides are:", shape.sides) //using dot operator to access "sides"

Использование квадратных скобок (также полезно для установки и удаления свойств)
Другой способ доступа к значениям - использование квадратных скобок []. Имя свойства, к которому нужно получить доступ, записывается в квадратных скобках в виде строки.

Здесь мы можем увидеть синтаксис метода квадратных скобок:

objectName['functionName']()

Вот пример того, как получить доступ к свойствам с помощью квадратных скобок:

//creating an object named shape var
shape = {
//defining properties of the object 
  //setting data values 
  name : 'square', sides : 4 
}
//accessing the properties using square brackets 
console.log("Name is:", shape['name']) //using square brackets to access "name"
console.log("Number of sides are:", shape['sides']) //using square brackets to access "sides"

Полезные ключевые слова: Get, Set, This.

Get
Ключевое слово get связывает свойство объекта с функцией. Теперь, когда это свойство ищется, вызывается функция получения. Возвращаемое значение функции получения определяет, какое свойство возвращается.

Установить
Синтаксис set связывает свойство объекта с функцией, вызываемой при попытке установить это свойство.

Это
this ключевое слово относится к объекту, поэтому вы можете получить доступ к его свойствам. Его также можно использовать для установки значения свойства в объекте.

Функции как объекты

Функции конструктора

Функции также являются объектами в JavaScript. Это потому, что, как и объекты, они имеют свои собственные свойства и методы. Функции также могут использоваться для создания объектов, и эти типы функций известны как функции-конструкторы.

Функции-конструкторы по существу избавляют от необходимости создавать отдельные литералы объектов для схожих задач. Они полезны, потому что вы часто будете сталкиваться с ситуациями, в которых вы не знаете, сколько объектов вы будете создавать; конструкторы предоставляют средства для эффективного создания сколь угодно большого количества объектов.

Вот синтаксис для реализации функции конструктора:

function FunctionName(parameter1, parameter2,...){ 
   //all the properties of the object are initialized here
   //functions to be provided by objects are defined here
}

Как видно из вышеизложенного:

  • Ключевое слово function используется для определения функции.
  • Имя функции конструктора должно быть написано с заглавной буквы, как FunctionName в приведенном выше фрагменте.
  • Тело этой функции в основном является конструкторской частью функции, поскольку она инициализирует свойства, устанавливая их равными соответствующим параметрам, передаваемым в функцию.

Вот пример функции-конструктора:

function Employee(_name, _age, _designation){ 
  this.name = _name 
  this.age = _age 
  this.designation = _designation 
}

Обратите внимание, что все объекты, созданные из Employee, будут содержать свойства имя, возраст и обозначение, где ключевое слово this может назначать определенные значения, даже если они являются частью одного и того же свойства.

Объекты-прототипы

Объекты-прототипы - это более простой подход для добавления новых методов / свойств в функцию-конструктор.

Свойства прототипа в объектах

Помимо свойств, которые вы создаете, существует дополнительное скрытое свойство, известное как свойство [[Prototype]], которое присутствует внутри каждого объекта, созданного из функции-конструктора. Свойство прототипа либо указывает на другой объект, либо имеет значение null.

Вот пример использования свойства Prototype:

//Shape object
var Shape= { 
  name: 'Rectangle', 
  sides: 4 
} 
//Rectangle object
var Rectangle = { 
  length: 3, 
  width: 5 
}
//setting [[Prototype]] of Rectangle equal to Shape Rectangle.__proto__ = Shape
//creating an object instance using Shape and Rectangle console.log("Name of shape is:",Rectangle.name) 
console.log("Number of sides are",Rectangle.sides) console.log("Length is:",Rectangle.length) console.log("Width is:",Rectangle.width)

Здесь мы видим, что когда для свойства прототипа Rectangle установлено значение Shape, он может получить доступ ко всем свойствам в Shape. Если свойство не найдено в объекте, например, свойство name не найдено в Rectangle, JavaScript автоматически возьмет его из прототипа этого объекта, Shape. Это известно как прототипное наследование, где строки 20 и 21 известны как унаследованные свойства; это основано на концепции цепочки прототипов.

Объектно-ориентированный JavaScript в ES6

JavaScript ES6 предлагает некоторые новые функции, а также улучшения. Одно из таких улучшений - введение ключевого слова class. Со всеми остальными нюансами ES6 вы можете ознакомиться здесь.

Тогда как в JavaScript ES5 конструкторы функций использовались для реализации концепции классов. Однако в версии ES6 используется ключевое слово class, которое очищает синтаксис для реализации той же концепции и упрощает понимание.

Объявление класса в JavaScript ES6

Синтаксис следующий:

class ClassName { 
  constructor() { 
    //initializing class properties 
  }
//class methods defined 
}

Одно из различий между функцией-конструктором и реализацией на основе классов состоит в том, что в первом случае тело функции действует как конструктор , где все свойства определены, тогда как в последнем существует отдельная функция-конструктор, определенная внутри класса, используемого для инициализации свойств.

Создание экземпляра объекта из класса

Здесь мы можем увидеть пример того, как создать экземпляр объекта из класса:

//creating a class named employee
class employee{ 
   //creating the constructor function
   constructor(name,age,designation){ 
   //all properties defined as they were in the constructor function
this.name = name this.age = age 
     this.designation = designation 
     this.displayName = function() {
console.log("Name is:",this.name) 
     } 
   } 
}
//creating an object instance named "employeeObj" 
var employeeObj = new employee('Joe',22,'Developer')
//displaying the properties of employeeObj 
employeeObj.displayName() 
console.log("Age is",employeeObj.age) 
console.log("Designation is:",employeeObj.designation)

Поскольку employee является самой функцией конструктора, метод создания экземпляра объекта из класса точно такой же, как и в версии ES5. Ключевое слово new используется для инициализации нового объекта employeeObj. Затем для этого объекта запускается метод constructor, присваивающий значениям, переданные в него, свойствам.

Определение методов в классе

Всякий раз, когда метод объявляется внутри класса, он определяется на прототипе этого класса. Это означает, что всякий раз, когда экземпляр объекта обращается к нему, он берется из прототипа соответствующего класса.

Вот пример:

//creating a class named employee
class employee { 
  //creating the constructor function
  constructor(name,age,designation){ 
   //all properties defined as they were in the constructor function
   this.name = name 
   this.age = age 
   this.designation = designation 
   this.displayName = function() { 
     console.log("Name is:",this.name) 
   } 
  } 
  //defining methods in a class 
  //getAge method returning the age of the current object 
  getAge(){ 
    return this.age 
  } 
}

Вот что происходит в приведенном выше коде:

  • Функция getAge определяется вне функции конструктора в строке 15.
  • Все такие методы хранятся в объекте-прототипе сотрудника.
  • Итак, новый объект, такой как employeeObj, имеет доступ ко всем методам, определенным в классе.
  • При вызове employeeObj метод getAge берется из employee.prototype.

Следующие шаги

Хотя JavaScript не может считаться языком ООП, использование версии ES6 (из-за использования классов) даст вам почувствовать, каково это - кодировать на более традиционном языке программирования ООП, таком как C / C ++. Основное различие между ES5 и ES6 заключается в добавлении и очистке синтаксиса.

Этот пост лишь коснулся поверхности объектно-ориентированного JavaScript. Есть еще много чего: статические методы, защитные свойства и инкапсуляция данных, и это лишь некоторые из них. Если вас интересует более подробная информация, вы можете изучить все основы с помощью ООП в JavaScript.