Класс в JavaScript: базовый синтаксис и примеры. Часть первая

Класс в JavaScript: базовый синтаксис и примеры. Часть первая

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

Одним из основных понятий в JavaScript является объект — это сущность, которая хранит свойства и методы, описывающие ее состояние и поведение.

Например, объект car может иметь свойства name, color, speed и методы start, stop, accelerate.

Для создания объектов в JavaScript существует несколько способов, но одним из самых удобных и современных является использование классов.

Что такое класс

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

Класс можно сравнить с фабрикой, которая производит объекты одного типа по заданному рецепту. Например, класс Car — это фабрика машин, которая принимает параметры name, color, speed и на их основе создает новые объекты car с соответствующими свойствами и методами.

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

Для определения классов в JavaScript можно использовать два способа: объявление класса или выражение класса.

Объявление класса — это способ определения класса с помощью ключевого слова class и имени класса, как мы делали ранее. Вот еще один пример:

class Car {
  constructor(name, color) {
    this.name = name;
    this.color = color;
  }
}

Выражение класса — это способ определения класса с помощью ключевого слова class и выражения, которое может быть именованным или анонимным, к примеру:

  • Анонимное выражение класса
let Car = class {
  constructor(name, color) {
    this.name = name;
    this.color = color;
  }
};
  • Именованное выражение класса
let Car = class Car2{
  constructor(name, color) {
    this.name = name;
    this.color = color;
  }
};

В обоих случаях мы присваиваем выражение класса переменной Car, которую можно использовать для создания объектов. Во втором случае имя выражения класса (Car2) доступно только внутри тела класса.

Посмотрите на часы! — сейчас самое время вам рассказать об одной особенности в определении классов.

Подъем (hoisting)

Объявление класса отличается от объявления функции тем, что объявление класса не поднимается (hoisted) в начало области видимости, в которой оно находится. Это означает, что нельзя использовать класс до того, как он будет определен. Если попытаться сделать это, будет выброшена ошибка ReferenceError.

Объяснение синтаксиса «class» на примере

Представьте, что нам нужно создать класс Car с тремя свойствами: name, color, speed и тремя методами: start, stop, accelerate.

Для определения класса мы будем использовать ключевое слово class, за которым следует имя класса (с большой буквы) и тело класса.

Тело класса — это фигурные скобки, внутри которых определяются конструктор, свойства и методы класса. Тело класса выполняется в строгом режиме (strict mode), что означает, что некоторые ошибки в коде будут более строго обрабатываться. Например, нельзя использовать необъявленные переменные или присваивать значения только для чтения свойствам.

Итак, начнем с объявления класса:

class Car {
	//Тело класса
}

Теперь можно указать конструктор с тремя свойствами:

class Car {
	constructor(name, color, speed) {
		this.name = name; this.color = color; this.speed = speed;
	}
}
Конструктор — метод, который вызывается при создании нового объекта и инициализирует его свойства. Он может быть только один в классе. Если constructor не указан явно, то используется конструктор по умолчанию, который не делает ничего.

В нашем случае конструктор принимает три параметра: name, color, speed и присваивает их соответствующим свойствам объекта через ключевое слово this.

И, наконец, добавим несколько методов:

class Car {
  constructor(name, color, speed) {
    this.name = name;
    this.color = color;
    this.speed = speed;
  }
  start() {
    console.log(this.name + ' завелась');
  }
  stop() {
    console.log(this.name + ' остановилась');
  }
  accelerate(value) {
    this.speed += value;
    console.log(this.name + ' разогналась до ' + this.speed + ' км/ч');
  }
}

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

Ну вот и все! Теперь можно создавать объекты.

Создание объектов

Для создания объектов на основе класса используется оператор new, за которым следует имя класса и круглые скобки с аргументами для конструктора, например:

let car1 = new Car("Audi", "black", 200);
let car2 = new Car("BMW", "white", 180);

В этом примере мы создали два объекта car1 и car2 на основе класса Car, передав в конструктор разные значения. Оба объекта имеют одинаковые методы, но разные свойства. Обращение к свойствам и методам объекта происходит через точку:

console.log(car1.name); // Audi
console.log(car2.color); // white
car1.start(); // Audi завелась
car2.accelerate(200); // BMW разогналась до 200 км/ч

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

В JavaScript можно расширять классы, то есть создавать новые классы на основе существующих. Это позволяет переиспользовать код и добавлять новую функциональность. Для расширения класса используется ключевое слово extends, за которым следует имя родительского класса.

Давайте создадим класс Truck, который расширяет класс Car. Класс Truck будет наследовать все свойства и методы класса Car, но к ним добавится свойство capacity (грузоподъемность) и новый метод load (загрузка):

class Truck extends Car {
  constructor(name, color, speed, capacity) {
    super(name, color, speed); // Вызываем конструктор родительского класса
    this.capacity = capacity; // Добавляем новое свойство
  }
  load(value) {
    if (value <= this.capacity) {
      console.log(this.name + ' загрузилась на ' + value + ' тонн');
    } else {
      console.log(this.name + ' не может загрузиться на ' + value + ' тонн');
    }
  }
}

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

Для создания объектов класса Truck также используется оператор new:

let truck1 = new Truck("Volvo", "red", 120, 10);
let truck2 = new Truck("MAN", "blue", 100, 15);

Объекты класса Truck имеют доступ к свойствам и методам как своего класса, так и родительского:

console.log(truck1.capacity); // 10
console.log(truck2.speed); // 100
truck1.start(); // Volvo завелась
truck2.load(12); // MAN загрузилась на 12 тонн

Геттеры и сеттеры

Геттеры и сеттеры — это специальные методы класса, которые позволяют получать и устанавливать значения свойств объекта. Они используются для контроля доступа к свойствам объекта, проверки входных данных и выполнения дополнительной логики.

Что такое геттер

Геттер — это метод, который возвращает значение свойства. Для его определения используется ключевое слово get перед именем метода. Геттер не принимает аргументов.

Пример геттера:

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }
  // Геттер для получения площади прямоугольника
  get area() {
    return this.width * this.height;
  }
}

Что такое сеттер

Cеттер — это метод, который присваивает значение свойству. Он принимает один аргумент — новое значение свойства, и определяется через ключевое слово set.

Пример сеттера:

class Rectangle {
	constructor(width, height) {
		this.width = width; this.height = height;
	}

	// Геттер для получения площади прямоугольника
	get area() {
		return this.width * this.height;
	}

	// Сеттер для установки ширины прямоугольника
	set width(value) {
		if (value > 0) {
			this.width = value;
		}
		else {
			console.log("Ширина должна быть положительной");
		}
	}

  // Сеттер для установки высоты прямоугольника
	set height(value){
		if (value > 0) {
			this.height = value;
		}
		else {
			console.log("Высота должна быть положительной");
		} 
	}
}

В этом примере мы определили класс Rectangle, который имеет два свойства: width (ширина) и height (высота) и один геттер: area (площадь). Мы также определили сеттеры для свойств width и height, которые проверяют, что значение больше нуля.

Сейчас мы создадим два объекта rect1 и rect2 на основе класса Rectangle и обратимся к их свойствам и геттерам. А также попытаемся изменить значения свойств с помощью сеттеров:

//Создаем два новых объекта
let rect1 = new Rectangle(10, 20);
let rect2 = new Rectangle(5, 15);

//Обращаемся к свойствам и геттерам
console.log(rect1.area); // 200
console.log(rect2.area); // 75

//Изменяем значения свойств с помощью сеттеров
rect1.width = -5; // Ширина должна быть положительной
rect2.height = 25;
console.log(rect1.area); // 200
console.log(rect2.area); // 125
Заметьте — геттеры и сеттеры вызываются как обычные свойства объекта, без скобок.

* Чтобы узнать продвинутые методы класса читайте вторую часть статьи тут.

Софья Пирогова

Софья Пирогова

Главный редактор / Автор статей
Георгий Бабаян

Георгий Бабаян

Основатель и CEO Эльбрус Буткемп