$ sudo teach IT
МОДУЛЬ 8 · УРОК 1

Классы и конструкторы

Объявление классов, конструкторы, свойства и методы в TypeScript

Цели урока

  • Понять, что такое классы и зачем они нужны в программировании
  • Научиться объявлять классы, добавлять свойства и методы
  • Освоить работу конструкторов и сокращённый синтаксис параметров
  • Понять модификаторы доступа: public, private, protected, readonly
  • Научиться создавать экземпляры классов и работать с ними
  • Разобрать практические примеры: User, BankAccount, Rectangle
  • Узнать типичные ошибки новичков и как их избежать

1. Что такое классы — аналогия и определение

Давайте начнём с самого главного вопроса: зачем вообще нужны классы?

Представьте, что вы работаете на конфетной фабрике. У вас есть огромная форма (литьевая форма), в которую заливается шоколад, и на выходе получаются одинаковые конфеты. Одна форма — много конфет. Каждая конфета имеет свою обёртку, свой вес, свой вкус, но все они сделаны по одному шаблону.

Аналогия:

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

В программировании класс — это шаблон для создания объектов. Он описывает:

  • Какие данные будет хранить объект (свойства / поля)
  • Что умеет делать объект (методы / функции)
  • Как создаётся объект (конструктор)

Ещё одна аналогия: класс — это чертёж дома. На чертеже написано: есть стены, есть крыша, есть двери, есть окна. Сам по себе чертёж не является домом — в нём нельзя жить. Но по этому чертежу можно построить сколько угодно домов, и каждый дом будет иметь свои обои, свою мебель, своих жильцов.

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

  • Группировать связанные данные и функции в одном месте
  • Создавать много одинаковых объектов из одного шаблона
  • Изменять код в одном месте, и это применится ко всем объектам
  • Делать код более понятным и структурированным
Важно:

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

2. Объявление класса — синтаксис и правила именования

Самый простой класс выглядит так:

class Dog {
}

Это пустой класс — без свойств, без методов, без конструктора. Он не очень полезен, но он уже рабочий. Разберём синтаксис:

  • class — ключевое слово, которое говорит «я объявляю класс»
  • Dog — имя класса
  • { } — тело класса, где живут свойства и методы
Правило именования:

Имена классов в TypeScript (и JavaScript) принято писать в PascalCase — каждое слово с заглавной буквы, без пробелов и подчёркиваний. Например: Dog, BankAccount, UserProfile, ShoppingCart. Это не синтаксическая ошибка написать myClass или my_class, но это нарушение конвенции, и опытные разработчики сразу заметят.

Давайте объявим более осмысленный класс с комментариями:

// Класс, описывающий книгу
class Book {
  title: string;
  author: string;
  pages: number;
}

Этот класс описывает книгу с тремя свойствами: название (title), автор (author) и количество страниц (pages). Пока что мы только описали структуру — сам по себе класс Book не является какой-то конкретной книгой. Он лишь говорит: «вот что значит быть книгой».

Совет:

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

Класс без тела тожедопустимыйен, но бесполезен:

class Empty {}

В реальной практике такой класс бесполезен, но он не вызывает ошибку. TypeScript позволяет создавать пустые классы — возможно, вы будете добавлять свойства позже.

3. Свойства класса (поля) — объявление и типизация

Свойства (поля) — это переменные, которые принадлежат классу. Они описывают состояние объекта. Если класс — это чертёж дома, то свойства — это «количество комнат», «этажность», «наличие гаража».

class Student {
  name: string;
  age: number;
  isEnrolled: boolean;
}

Здесь у нас три свойства:

  • name — строка, имя студента
  • age — число, возраст студента
  • isEnrolled — булево значение, записан ли студент

Можно задавать начальные значения (дефолтные значения) сразу:

class Settings {
  theme: string = "light";
  fontSize: number = 14;
  notifications: boolean = true;
}

Теперь, когда мы создадим объект класса Settings, его свойства уже будут иметь значения по умолчанию: тема «light», размер шрифта 14, уведомления включены.

Свойства могут быть различными типами, включая массивы и объекты:

class Playlist {
  name: string;
  tracks: string[];
  duration: number;
  isPublic: boolean;
}
Совет:

Всегда указывайте типы для свойств класса. TypeScript может вывести тип автоматически, но явная типизация делает код более понятным и помогает отловить ошибки на ранней стадии. Никогда не пишите просто name; без типа — это вызовет ошибку.

Также свойства могут иметь типы-ссылки на другие типы:

type Address = {
  street: string;
  city: string;
};

class Person {
  name: string;
  address: Address;
}

4. Конструктор — зачем нужен и как работает

Конструктор — это специальный метод, который вызывается автоматически при создании нового объекта (экземпляра) класса. Его главная задача — задать начальные значения свойствам.

Аналогия:

Конструктор — это как инструкция по сборке мебели из IKEA. Когда вы покупаете шкаф, он приходит в коробке. Конструктор — это тот процесс, где из коробки получается готовый шкаф с определёнными параметрами: цвет, размер, количество полок.

Синтаксис конструктора:

class User {
  name: string;
  email: string;

  constructor(name: string, email: string) {
    this.name = name;
    this.email = email;
  }
}

Разберём по частям:

  • constructor — ключевое слово, обозначающее конструктор
  • (name: string, email: string) — параметры конструктора
  • this.name = name — присваиваем значение параметра свойству класса

Здесь возникает важный вопрос: что такое this?

this — это ссылка на текущий объект, то есть на тот экземпляр класса, который создаётся или уже существует. Когда мы пишем this.name, мы говорим: «возьми свойство name текущего объекта».

Почему нужен this?

Параметр конструктора name и свойство класса name — это две разные переменные. Они могут иметь одно имя, но это не одно и то же. this.name — это свойство объекта, а просто name — это значение параметра. Без this TypeScript не сможет понять, о чём идёт речь.

Теперь, когда мы создаём объект, конструктор автоматически вызывается:

// Создаём экземпляр класса User
const user1 = new User("Алексей", "alex@mail.ru");

// TypeScript автоматически вызывает конструктор
// конструктор выполняет: this.name = "Алексей"; this.email = "alex@mail.ru";

console.log(user1.name);   // "Алексей"
console.log(user1.email); // "alex@mail.ru"

Ключевое слово new создаёт новый объект и запускает конструктор. Без new класс не может породить объект.

Конструктор может иметь любое количество параметров — от нуля до скольки угодно:

// Конструктор без параметров
class Color {
  r: number;
  g: number;
  b: number;

  constructor() {
    this.r = 0;
    this.g = 0;
    this.b = 0;
  }
}

// Конструктор с одним параметром
class Counter {
  value: number;

  constructor(startValue: number) {
    this.value = startValue;
  }
}

// Конструктор с тремя параметрами
class Product {
  name: string;
  price: number;
  category: string;

  constructor(name: string, price: number, category: string) {
    this.name = name;
    this.price = price;
    this.category = category;
  }
}
Важно:

Конструктор может быть только один в классе. JavaScript (и TypeScript) не поддерживают перегрузку конструкторов как, например, Java. Если вам нужно создавать объекты по-разному, используйте параметры с значениями по умолчанию или статические методы.

Параметры конструктора могут иметь значения по умолчанию:

class Car {
  brand: string;
  year: number;

  constructor(brand: string, year: number = 2024) {
    this.brand = brand;
    this.year = year;
  }
}

const car1 = new Car("Toyota"); // year = 2024 по умолчанию
const car2 = new Car("BMW", 2020); // year = 2020

5. Методы класса — функции внутри класса

Методы — это функции, которые принадлежат классу. Если свойства описывают состояние объекта (что он имеет), то методы описывают поведение (что он умеет делать).

Аналогия:

Свойства — это «что есть у человека» (имя, возраст, рост). Методы — это «что человек умеет делать» (ходить, говорить, есть). Класс описывает и то, и другое вместе.

Синтаксис метода:

class Calculator {
  result: number = 0;

  add(value: number): void {
    this.result += value;
  }

  subtract(value: number): void {
    this.result -= value;
  }

  getResult(): number {
    return this.result;
  }
}

Здесь:

  • add(value: number): void — метод, который принимает число и ничего не возвращает (void)
  • subtract(value: number): void — аналогично
  • getResult(): number — метод, который возвращает число

Использование:

const calc = new Calculator();
calc.add(10);
calc.add(5);
calc.subtract(3);
console.log(calc.getResult()); // 12

Методы могут обращаться к свойствам через this и вызывать другие методы:

class Greeting {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  getGreeting(): string {
    return `Привет, ${this.name}!`;
  }

  logGreeting(): void {
    const message = this.getGreeting();
    console.log(message);
  }
}

Методы также могут принимать необязательные параметры:

class Logger {
  log(message: string, prefix?: string): void {
    const formattedMessage = prefix
      ? `[${prefix}] ${message}`
      : message;
    console.log(formattedMessage);
  }
}

const logger = new Logger();
logger.log("Загрузка завершена"); // "Загрузка завершена"
logger.log("Загрузка завершена", "INFO"); // "[INFO] Загрузка завершена"
Совет:

Методы класса не нуждаются в ключевом слове function. Они объявляются просто как имяМетода() { }. Это особенность синтаксиса классов.

6. Создание экземпляров — new ClassName()

Экземпляр (instance) — это конкретный объект, созданный по шаблону класса. Мы уже видели примеры выше, но давайте разберём подробнее.

class Fruit {
  name: string;
  color: string;

  constructor(name: string, color: string) {
    this.name = name;
    this.color = color;
  }
}

// Создаём три экземпляра одного класса
const apple = new Fruit("Яблоко", "красное");
const banana = new Fruit("Банан", "жёлтый");
const grape = new Fruit("Виноград", "фиолетовый");

// Каждый экземпляр — независимый объект
console.log(apple.name);    // "Яблоко"
console.log(banana.color); // "жёлтый"
console.log(grape.name);   // "Виноград"

Каждый вызов new Fruit(...) создаёт новый независимый объект. Изменение одного объекта не влияет на другие:

// Добавим метод в класс Fruit
class Fruit {
  name: string;
  color: string;

  constructor(name: string, color: string) {
    this.name = name;
    this.color = color;
  }

  describe(): string {
    return `${this.name} — ${this.color}`;
  }
}

const apple = new Fruit("Яблоко", "красное");
const banana = new Fruit("Банан", "жёлтый");

console.log(apple.describe());   // "Яблоко — красное"
console.log(banana.describe()); // "Банан — жёлтый"

Мы можем создавать переменные с типом класса:

// Явное указание типа
const apple: Fruit = new Fruit("Яблоко", "красное");

// TypeScript выведет тип автоматически
const banana = new Fruit("Банан", "жёлтый");
Совет:

В большинстве случаев TypeScript сам выведет тип экземпляра. Указывать тип явно (const apple: Fruit = new Fruit(...)) нужно только когда это действительно помогает — например, при объявлении переменной без инициализации.

7. Сокращённый синтаксис конструктора (parameter properties)

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

Сначала посмотрим на «длинный» способ, который мы уже знаем:

// Длинный способ — объявляем свойства и копируем в конструкторе
class User {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

А теперь — короткий способ с помощью модификаторов в параметрах конструктора:

// Короткий способ — модификаторы в параметрах
class User {
  constructor(public name: string, public age: number) {}
}

Это делает ровно то же самое! TypeScript автоматически:

  • Объявляет свойства name и age в классе
  • Генерирует код this.name = name; this.age = age;

Давайте сравним:

// Длинный способ (8 строк)
class User {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

// Короткий способ (3 строки)
class User {
  constructor(public name: string, public age: number) {}
}

Модификаторы, которые можно использовать в параметрах конструктора:

public Свойство доступно везде (по умолчанию)
private Свойство доступно только внутри класса
protected Свойство доступно внутри класса и его наследников
readonly Свойство можно задать только один раз (в конструкторе)

Пример с разными модификаторами:

class Employee {
  constructor(
    public name: string,           // доступно всем
    private salary: number,      // только внутри класса
    protected department: string, // класс и наследники
    readonly id: number          // нельзя изменить
  ) {}
}
Совет:

Сокращённый синтаксис конструктора — это стандарт де-факто в TypeScript. Используйте его каждый раз, когда нужно просто скопировать параметры в свойства. Длинный способ оставьте для случаев, когда в конструкторе есть дополнительная логика.

8. Модификаторы доступа — public, private, protected, readonly

Модификаторы доступа — это правила видимости. Они определяют, кто может «видеть» и «использовать» свойства и методы класса.

Аналогия:

Представьте квартиру в многоквартирном доме. public — это лестница, доступная всем. private — это ваша комната, куда никто другой не может зайти. protected — это ваша квартира, куда могут зайти только члены вашей семьи (наследники).

public — доступно всем

class Car {
  constructor(
    public brand: string,
    public color: string
  ) {}
}

const car = new Car("Toyota", "белый");
console.log(car.brand);  // "Toyota" ✓
car.color = "чёрный"; // ✓ можно изменить

private — доступно только внутри класса

class BankAccount {
  constructor(
    public owner: string,
    private balance: number
  ) {}

  deposit(amount: number): void {
    this.balance += amount;
  }

  getBalance(): number {
    return this.balance;
  }
}

const account = new BankAccount("Иван", 1000);
console.log(account.owner);       // "Иван" ✓
console.log(account.balance);    // ✗ Ошибка: Property 'balance' is private
account.balance = 999999;        // ✗ Ошибка: Property 'balance' is private
account.deposit(500);            // ✓ Через метод можно
console.log(account.getBalance()); // 1500

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

protected — доступно классу и его наследникам

class Animal {
  constructor(
    public name: string,
    protected energy: number
  ) {}

  eat(food: number): void {
    this.energy += food;
  }
}

// Dog — наследник Animal
class Dog extends Animal {
  fetch(): void {
    // Dog может обращаться к protected свойству
    this.energy -= 10;
  }
}

const dog = new Dog("Шарик", 100);
console.log(dog.name);     // "Шарик" ✓
console.log(dog.energy);   // ✗ Ошибка: Property 'energy' is protected

readonly — только для чтения

class Config {
  constructor(
    public readonly version: string,
    public name: string
  ) {}
}

const config = new Config("1.0.0", "MyApp");
console.log(config.version); // "1.0.0" ✓
config.version = "2.0.0";  // ✗ Ошибка: Cannot assign to 'version' because it is a read-only property
config.name = "NewApp";   // ✓ Обычное свойство можно менять
Важно:

readonly работает как во время выполнения, так и на уровне типов. Даже если вы попытаетесь изменить readonly свойство через JavaScript-трюки, TypeScript покажет ошибку. Однако в рантайме (обычный JS) readonly свойства всё же можно изменить — TypeScript проверяет только на этапе компиляции.

9. Метод toString() — красивое представление объекта

Метод toString() возвращает строковое представление объекта. По умолчанию он возвращает что-то вроде [object Object], что не очень информативно. Мы можем переопределить его:

class Person {
  constructor(
    public name: string,
    public age: number
  ) {}

  toString(): string {
    return `Person(name: ${this.name}, age: ${this.age})`;
  }
}

const person = new Person("Анна", 25);
console.log(person.toString()); // "Person(name: Анна, age: 25)"
// toString() вызывается автоматически при преобразовании в строку:
console.log("Пользователь: " + person); // "Пользователь: Person(name: Анна, age: 25)"

Метод toString() автоматически вызывается при:

  • Конкатенации строки с объектом: "User: " + obj
  • Вызове String(obj)
  • Вызове obj.toString() вручную
  • При использовании шаблонных строк: `${obj}`
Совет:

Всегда переопределяйте toString() в классах, которые будут использоваться в логировании или отладке. Это значительно упрощает отслеживание проблем.

10. Типизация this в методах

TypeScript обычно автоматически выводит тип this в методах класса. Но иногда возникают ситуации, когда нужно указать тип явно.

class Point {
  constructor(
    public x: number,
    public y: number
  ) {}

  // TypeScript автоматически определяет тип this как Point
  distanceTo(other: Point): number {
    // this имеет тип Point, поэтому this.x и this.y — числа
    const dx = this.x - other.x;
    const dy = this.y - other.y;
    return Math.sqrt(dx * dx + dy * dy);
  }

  // Явная типизация this — полезно для цепочки вызовов
  moveX(delta: number): this {
    this.x += delta;
    return this;
  }

  moveY(delta: number): this {
    this.y += delta;
    return this;
  }
}

// Благодаря типу this, можно строить цепочки вызовов:
const point = new Point(0, 0);
point.moveX(5).moveY(3);
console.log(point.x, point.y); // 5 3

Тип this как возвращаемое значение полезен для паттерна Fluent Interface (цепочки вызовов). Когда метод возвращает this, можно вызывать следующий метод сразу:

// Без возврата this — пришлось бы писать так:
point.moveX(5);
point.moveY(3);

// С возвратом this — компактно и читаемо:
point.moveX(5).moveY(3);

11. Практические примеры

Пример 1: Класс User

class User {
  login: string;
  email: string;
  age: number;
  isVerified: boolean = false;

  constructor(
    login: string,
    email: string,
    age: number
  ) {
    this.login = login;
    this.email = email;
    this.age = age;
  }

  verify(): void {
    this.isVerified = true;
    console.log(`Пользователь ${this.login} верифицирован!`);
  }

  isAdult(): boolean {
    return this.age >= 18;
  }

  toString(): string {
    return `User(${this.login}, ${this.age}, verified: ${this.isVerified})`;
  }
}

const user1 = new User("coder42", "coder@mail.ru", 22);
user1.verify(); // "Пользователь coder42 верифицирован!"
console.log(user1.isAdult()); // true
console.log(user1.toString()); // "User(coder42, 22, verified: true)"

Пример 2: Класс BankAccount

class BankAccount {
  private balance: number;
  private history: string[] = [];

  constructor(
    public owner: string,
    initialBalance: number = 0
  ) {
    if (initialBalance < 0) {
      throw new Error("Начальный баланс не может быть отрицательным");
    }
    this.balance = initialBalance;
    this.history.push(`Открыт счёт: ${initialBalance} руб.`);
  }

  deposit(amount: number): void {
    if (amount <= 0) {
      throw new Error("Сумма пополнения должна быть положительной");
    }
    this.balance += amount;
    this.history.push(`Пополнение: +${amount} руб.`);
  }

  withdraw(amount: number): void {
    if (amount > this.balance) {
      throw new Error("Недостаточно средств");
    }
    this.balance -= amount;
    this.history.push(`Снятие: -${amount} руб.`);
  }

  getBalance(): number {
    return this.balance;
  }

  getHistory(): string[] {
    return [...this.history];
  }

  toString(): string {
    return `Счёт ${this.owner}: ${this.balance} руб.`;
  }
}

const account = new BankAccount("Иван Иванов", 10000);
account.deposit(5000);
account.withdraw(3000);
console.log(account.getBalance());   // 12000
console.log(account.getHistory());
// ["Открыт счёт: 10000 руб.", "Пополнение: +5000 руб.", "Снятие: -3000 руб."]

Пример 3: Класс Rectangle

class Rectangle {
  constructor(
    public readonly width: number,
    public readonly height: number
  ) {
    if (width <= 0 || height <= 0) {
      throw new Error("Ширина и высота должны быть положительными");
    }
  }

  area(): number {
    return this.width * this.height;
  }

  perimeter(): number {
    return 2 * (this.width + this.height);
  }

  isSquare(): boolean {
    return this.width === this.height;
  }

  toString(): string {
    return `Прямоугольник(${this.width} × ${this.height})`;
  }
}

const rect = new Rectangle(10, 5);
console.log(rect.area());     // 50
console.log(rect.perimeter()); // 30
console.log(rect.isSquare());  // false

const square = new Rectangle(7, 7);
console.log(square.isSquare()); // true

12. Частые ошибки при работе с классами

Давайте разберём ошибки, которые чаще всего допускают новички при работе с классами.

Ошибка 1: Забыли объявить тип свойства

// ❌ Ошибка: Property 'name' has no initializer
class User {
  name: string;
}

// ✅ Правильно: задали начальное значение
class User {
  name: string = "";
}

// ✅ Или используем сокращённый синтаксис
class User {
  constructor(public name: string) {}
}

Ошибка 2: Забыли this перед свойством

// ❌ Ошибка: переменная name в конструкторе — это параметр, а не свойство
class User {
  name: string;

  constructor(name: string) {
    name = name;  // ❌ Это не присваивает свойству!
  }
}

// ✅ Правильно:
class User {
  name: string;

  constructor(name: string) {
    this.name = name;  // ✅ this ссылается на свойство класса
  }
}

Ошибка 3: Забыли new при создании объекта

// ❌ Ошибка: вы вызвали класс как функцию
class User {
  constructor(public name: string) {}
}

const user = User("Алексей"); // ❌ TypeError: User is not a constructor

// ✅ Правильно:
const user = new User("Алексей"); // ✅

Ошибка 4: Доступ к приватному свойству снаружи

// ❌ Ошибка: Property 'password' is private
class User {
  constructor(
    public name: string,
    private password: string
  ) {}
}

const user = new User("Алексей", "secret123");
console.log(user.password); // ❌ Ошибка компиляции

// ✅ Правильно: добавить метод для доступа
class User {
  constructor(
    public name: string,
    private password: string
  ) {}

  checkPassword(input: string): boolean {
    return input === this.password;
  }
}

Ошибка 5: Попытка изменить readonly свойство

// ❌ Ошибка: Cannot assign to 'id' because it is a read-only property
class Product {
  constructor(
    public readonly id: number,
    public name: string
  ) {}
}

const product = new Product(1, "Ноутбук");
product.id = 2; // ❌ Ошибка компиляции

// ✅ Если нужно менять id, уберите readonly:
class Product {
  constructor(
    public id: number,
    public name: string
  ) {}
}

Ошибка 6: Использование стрелочных функций как методов

// ⚠️ Не рекомендуется: стрелочные функции как методы
class Timer {
  seconds = 0;

  // Стрелочная функция создаётся при каждом создании экземпляра
  // Это использует больше памяти
  tick = (): void => {
    this.seconds++;
  }

  // Обычный метод создаётся один раз на класс
  start(): void {
    // Здесь this будет зависеть от контекста вызова
    setInterval(this.tick, 1000);
  }
}
Совет:

Стрелочные функции как классовые свойства — это отдельная тема. Для начинающих рекомендуется использовать обычные методы. Стрелочные функции могут быть полезны, когда нужно сохранить контекст this, например при передаче метода как колбэка. Но это тема для продвинутых курсов.

Практическое задание

Создайте класс Car со следующими требованиями:

  • Свойства: brand (string), model (string), year (number), mileage (number, по умолчанию 0)
  • Конструктор принимает brand, model, year. Mileage автоматически = 0
  • Метод drive(km: number): void — увеличивает пробег
  • Метод getInfo(): string — возвращает строку "Toyota Camry 2020, пробег: 15000 км"
  • Метод isOld(): boolean — возвращает true, если год выпуска старше 2015
  • Метод toString(): string — переопределите для красивого вывода

Используйте сокращённый синтаксис конструктора там, где уместно. Добавьте модификаторы доступа: year — readonly, mileage — private (доступен только через метод drive).

Чек-лист урока

  • Класс — шаблон для создания объектов, содержащий свойства и методы
  • class ClassName {} — объявление класса, имя пишется в PascalCase
  • Свойства — переменные внутри класса, описывающие состояние объекта
  • Типизация свойств — обязательно указывайте типы для каждого свойства
  • constructor() — специальный метод, вызываемый при создании объекта
  • this — ссылка на текущий экземпляр класса
  • Методы — функции внутри класса, описывающие поведение объекта
  • new ClassName() — создание нового экземпляра класса
  • Сокращённый синтаксис — public/private/protected в параметрах конструктора автоматически создаёт свойства
  • public — доступно всем (по умолчанию)
  • private — доступно только внутри класса
  • protected — доступно классу и его наследникам
  • readonly — свойство можно задать только один раз (в конструкторе)
  • toString() — метод для красивого строкового представления объекта
  • Тип this — позволяет строить цепочки вызовов (Fluent Interface)
  • Типичные ошибки — забыли this, забыли new, доступ к private, изменение readonly

Тест по классам и конструкторам

8 вопросов

Класс с параметрами конструктора

Premium

Класс Book с вычисляемым свойством

Premium