☕ Учебник по JavaScript: ООП на простых примерах

Познакомимся с наследованием, инкапсуляцией, абстракцией и полиморфизмом. А также научимся создавать объекты и использовать синтаксический сахар class.
☕ Учебник по JavaScript: ООП на простых примерах

Что такое ООП?

Объектно-ориентированное программирование (ООП) – это парадигма программирования, основанная на концепции классов и объектов. Она используется для структурирования программы на основе объектов, обычно называемых классами.

Объект имеет в себе поля и методы. В качестве полей выступают различные типы данных, такие как int, string и т. д. В качестве методов – функция, которая выполняет то или иное действие. В качестве примера возьмем клиента банка.

У клиента есть:

  • Имя.
  • Фамилия.
  • Отчество.
  • ИНН.
  • и т. д.

Приведенные выше параметры являются полями у объекта. Но не будет забывать про методы. Что может делать клиент:

  • Снимать деньги.
  • Пополнять.
  • Оплачивать.
  • Открыть счет.
  • и т. д.

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

Итог: ООП это парадигма программирования, в которой используется объект, состоящий из полей и методов.

Способы создания объекта в JavaScript

Есть несколько способов создания объектов в JS. Пример создания объекта с полями и методами:

        const book = {
	title: “War and Peace”,
	author: “Leo Tolstoy”,
	summary: function () {
		console.log(`${this.title} is written by ${this.author}`);
	}

}

const book1 = {
	title: “The Captain's Daugther”,
	author: “Alexander Pushkin”,
	summary: function () {
		console.log(`${this.title} is written by ${this.author}`);
	}
}
    

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

        function Book(title, author) {
	this.author = author;
	this.title = title;
}
const book1 = new Book(“War and Peace”, “Leo Tolstoy”);
const book1 = new Book(“The Captains Daughter”, “Alexander Pushkin”);
    

Таким образом, конструктор объекта помогает нам повторно использовать литерал объекта.

ES6 – class и синтаксический сахар

В ES6 был добавлен синтаксический сахар class. Класс – это абстрактное представление объекта, который облегчает использование ООП в JavaScript. Пример использования показан ниже.

        class User {
	#password;
	constructor(name, userName, password) {
		this.name = name;
		this.userName = userName;
		this.#password = password;
	}

	login(userName, password) {
	
		if (userName === this.userName && password === this.#password) {
			console.log('Login Successfully');
		} else {
			console.log('Authentication Failed!!');
		}
	
	}

	setPassword(newPassword) {
		this.#password = newPassword;
	}
	
};

const user = new User('Test testov', test_testov, 'password:)');
user.login('nehal_mahida', 'password:)'); // Login Successfully

console.log(user.name); // Nehal Mahida
console.log(user.password); // undefined
console.log(user.#password); // Syntax Error

user.setPassword('new_password:)');
user.login('nehal_mahida', 'password:)'); // Authentication Failed!!
user.login('nehal_mahida', 'new_password:)'); // Login Successfully
    

Класс User имеет поля и методы. В данном примере name, userName, password являются полями класса. Также представлен метод login, который при верном пароле и логине выводит соответствующее сообщение.

При создании объекта из класса с помощью ключевого слова new, JavaScript внутренне вызывает метод конструктора, который инициализирует публичные и приватные свойства класса.

По умолчанию все свойства, объявленные в классе, являются публичными. Их можно вызывать и изменять вне класса. Здесь name и userName являются публичными свойствами.

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

Для печати/изменения приватных свойств нам нужны методы getter/setter. Например, метод setPassword является тем самым setter, который изменяет значение password.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

Наследование

При наследовании один класс получает свойства и методы другого класса. Класс, который наследует свойство, называется подклассом или дочерним классом. Класс, свойства которого наследуются, называется суперклассом или родительским классом.

Наследование является основной парадигмой ООП. Преимуществом наследования является возможность повторного использования написанного кода. Когда дочерний класс наследует методы от родительского класса, нам не нужно переписывать уже написанные методы, которые были в родительском классе.

        class User {

	#password;

	constructor(email, password) {
		this.email = email;
		this.#password = password;
	}

	login(email, password) {
		if (email === this.email && password === this.#password) {
			console.log('Login Successfully');
		} else {
			console.log('Authentication Failed!!');
		}
	}

	resetPassword(newPassword) {
		this.#password = newPassword;
	}

	logout() {
		console.log('Logout Successfully');
	}
}

class Author extends User {

	#numOfPost;
	
	constructor(email, password) {
		super(email, password);
		this.#numOfPost = 0;
	}

	createPost(content) {
		// add content to your DB. :)
		this.#numOfPost++;
	}
	
	getNumOfPost() {
		return this.#numOfPost;
	}
	
}

class Admin extends User {

	constructor(email, password) {
		super(email, password);
	}
	
	removeUser(userId) {
		// remove this userId from your DB.
		console.log('User Removed successfully.');
	}
	
}

const user = new Author('user@gmail.com', 'password:)');
user.login('user@gmail.com', 'password:)');
user.createPost('Leo Tolstoy is the Russian author');
console.log(user.getNumOfPost()); // 2

const admin = new Admin('admin@gmail.com', 'password');
admin .login('admin@gmail.com', 'password');
admin .resetPassword('newpassword');
admin .login('admin@gmail.com', 'newpassword');
admin .removeUser(2);
    

В приведенном выше примере классы Author и Admin наследуют свойство класса User с помощью ключевых слов extends и super.

Ключевое слово extends используется для установления отношений родитель-ребенок между двумя классами. В первом случае Author становится подклассом, а User – родительским классом.

Подкласс имеет доступ ко всем публичным и защищенным членам суперкласса. Кроме того, он может иметь свои собственные свойства и методы. Так мы можем достичь повторного использования через наследование.

Ключевое слово super – это специальное ключевое слово. Вызов super в конструкторе дочернего класса вызывает конструктор родительского. Так мы инициализируем свойства в классах Author и Admin.

Инкапсуляция

Инкапсуляция определяется как связывание данных и методов в единое целое для защиты от доступа извне, подобно тому как таблетка содержит лекарство внутри своей оболочки.

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

Это похоже на создание метода getter/setter для private свойств, которые объявляются в классе.

В приведенном выше примере уже использована инкапсуляция. Например, изменение пароля для User c помощью метода resetPassword, где идет обращение к private свойству password, чтобы изменить значение.

Абстракция

Люди часто путают инкапсуляцию с абстракцией. Абстракция – демонстрация только основных вещей и сокрытие внутренней реализации.

Рассмотрим пример с автомобилем. Автомобиль выполняет некоторые действия, такие как старт, движение и остановка. Каждое действие приводит к результату. Плюс, эти действия имеют определенные поддействия, которые скрыты от вас, но вам не нужно заботиться об этих поддействиях. Например, пользователь не должен понимать, как работает зажигание или как поступает бензин, а важно знать, что есть кнопка старт, которая запускает двигатель.

Пример использования в JavaScript:

        class User {
  name;
  email;
  #password;
  constructor() {}

  #validateEmail(email) {
    // проверка email на валидность.
    return true;
  }

  #validatePassword(password) {
    // проверка на валидность пароля
    return true;
  }

  signUp(name, email, password) {
    let isValidated = false;
    isValidated = this.#validateEmail(email);
    isValidated &&= this.#validatePassword(password);

    if (isValidated) {
      this.name = name;
      this.email = email;
      this.#password = password;
      // добавляем пользователя в базу данных
      console.log('User registered successfuly');
    } else {
      console.log('Please enter correct Details!!');
    }
  }

  login(email, password) {
    if (email === this.email && password === this.#password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }

  #isRegisteredUser(email) {
    // проверка пользователя на наличие регистрации
    return true;
  }

  resetPassword(email, newPassword) {
    if (this.#isRegisteredUser(email)) {
        this.#password = newPassword;
        console.log('Operation performed successfully');
    }
    else {
      console.log('No account found!');
    }
  }
};

const author= new User();
author.signUp('Max Andreyev', 'author@gmail.com', 'password:)'); // User registered successfully

author.#validateEmail('author@gmail.com'); // Syntax Error.

author.login('author@gmail.com', 'password:)'); // Login Successfully
author.resetPassword('author@gmail.com', ''); // Operation performed successfully
    

Вышеуказанный пример наглядно показывает использование абстракции в JavaScript. Например, для пользователя достаточно только иметь метод sign up (регистрация), а все остальное знать необязательно.

Полиморфизм

Полиморфизм уменьшает дублирование участков кода. Существуют два типа использования полиморфизма:

  • Полиморфизм во время компиляции
  • Полиморфизм во время выполнения

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

Переопределение методов – это тип полиморфизма во время выполнения. Например, используется для переопределения методов родительского класса в дочернем классе.

Пример использования в JavaScript:

        class User {
  constructor(email, password) {
    this.email = email;
    this.password = password;
  }

  login(email, password) {
    if (email === this.email && password === this.password) {
      console.log('Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }
}

class Author extends User {
  #numOfPost;

  constructor(email, password) {
    super(email, password);
    this.#numOfPost = 0;
  }

  createPost(content) {
    this.#numOfPost++;
  }

  getNumOfPost() {
    return this.#numOfPost;
  }
}

class Admin extends User {
  constructor(email, password) {
    super(email, password);
  }

  login(email, password) {
		const isAdminValid = true; 
		// делаем проверку на валидность администратора
		// например 2-ух факторная идентификация
    if (email === this.email && password === this.password && isAdminValid == true) {
      console.log('Admin Login Successfully');
    } else {
      console.log('Authentication Failed!!');
    }
  }

  removeUser(userId) {
    console.log('User Removed successfully.');
  }
}

const author= new Author('author@gmail.com', 'password:)');
author.login('author@gmail.com', 'password:)'); // Login Successfully

const admin= new Admin('admin@gmail.com', 'password');
admin.login('admin@gmail.com', 'password'); // Admin Login Successfully
    

В примере Author и Admin наследуются от класса User. Оба класса имеют метод login, который принадлежит User. Только для администратора необходимо поставить дополнительный уровень проверки. Это достигается с помощью переопределения метода login и добавления дополнительных проверок. Просто перезаписываем название. Таким образом, можно достичь полиморфизма в JavaScript.

***

Материалы по теме

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ