Поиск по сайту
Ctrl + K
Вопросы по JS

В чем различия между классами ES2015 и функциями-конструкторами ES5 в JavaScript?

JavaScript прошел через значительные изменения с появлением ES2015 (ES6), в том числе введение классов. Это привело к некоторым изменениям в том, как создаются объекты и наследование в языке. Однако многие разработчики по-прежнему используют старые способы, такие как функции-конструкторы из ES5. Давайте рассмотрим различия между ними.

1. Синтаксис и читаемость

ES5: Функции-конструкторы

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

function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person1 = new Person("Alice", 30);
console.log(person1.name);  // "Alice"
console.log(person1.age);   // 30

ES2015: Классы

С выходом ES6 был введён новый синтаксис для создания классов, который более близок к классическим объектно-ориентированным языкам программирования.

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const person1 = new Person("Alice", 30);
person1.greet();  // "Hello, my name is Alice"

Классы в ES6 обеспечивают более понятный и удобочитаемый синтаксис, чем функции-конструкторы ES5.

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

ES5: Наследование через прототипы

В ES5 наследование реализуется через прототипы. Это требует явного присваивания метода дочернему объекту.

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a noise`);
};

function Dog(name) {
  Animal.call(this, name);  // Вызов конструктора родителя
}

Dog.prototype = Object.create(Animal.prototype);  // Наследование от Animal
Dog.prototype.constructor = Dog;

const dog = new Dog("Buddy");
dog.speak();  // "Buddy makes a noise"

ES2015: Наследование через классы

В ES6 классы облегчают работу с наследованием. Используется ключевое слово extends для указания класса-предка и super() для вызова конструктора родительского класса.

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name);  // Вызов конструктора родителя
  }
}

const dog = new Dog("Buddy");
dog.speak();  // "Buddy makes a noise"

В ES6 наследование стало проще и более интуитивно понятным.

3. Методы

ES5: Методы в прототипе

В ES5 методы обычно добавляются в prototype функции-конструктора. Это позволяет всем объектам, созданным с помощью этого конструктора, наследовать эти методы.

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name}`);
};

const person1 = new Person("Alice");
person1.sayHello();  // "Hello, my name is Alice"

ES2015: Методы в классе

В ES6 методы можно определять прямо в теле класса. Это значительно упрощает код и делает его более читаемым.

class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const person1 = new Person("Alice");
person1.sayHello();  // "Hello, my name is Alice"

В ES6 нет необходимости явно добавлять методы в prototype, это происходит автоматически.

4. Конструктор и методы

ES5: Конструктор

Конструкторы в ES5 являются обычными функциями, которые используют this для создания объекта.

function Person(name) {
  this.name = name;
}

ES2015: Конструктор и методы

В ES6 конструкция constructor является специальным методом, который вызывается при создании нового объекта через new.

class Person {
  constructor(name) {
    this.name = name;
  }
}

При этом методы, определенные в классе, автоматически добавляются в prototype этого класса.

5. Геттеры и сеттеры

ES5: Геттеры и сеттеры

В ES5 нужно использовать Object.defineProperty() для создания геттеров и сеттеров.

function Person(name) {
  this.name = name;
}

Object.defineProperty(Person.prototype, "name", {
  get: function() {
    return this._name;
  },
  set: function(value) {
    this._name = value;
  }
});

const person1 = new Person("Alice");
console.log(person1.name);  // "Alice"
person1.name = "Bob";
console.log(person1.name);  // "Bob"

ES2015: Геттеры и сеттеры

В ES6 можно использовать синтаксис геттеров и сеттеров прямо в теле класса.

class Person {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name;
  }

  set name(value) {
    this._name = value;
  }
}

const person1 = new Person("Alice");
console.log(person1.name);  // "Alice"
person1.name = "Bob";
console.log(person1.name);  // "Bob"

6. Вызов конструктора без new

ES5: Невозможно вызвать без new

Если вызвать функцию-конструктор без ключевого слова new, то это приведет к ошибке. Например:

const person1 = Person("Alice");  // Ошибка: `this` будет неопределен

ES2015: Классы требуют new

В ES6 классы всегда требуют явного вызова через new. Если попытаться вызвать класс без new, то будет выброшена ошибка.

const person1 = Person("Alice");  // TypeError: Class constructor Person cannot be invoked without 'new'

Заключение

  • Синтаксис: ES6 предоставляет более чистый, понятный и современный синтаксис для работы с объектами и наследованием.
  • Наследование: В ES6 наследование через extends и super() значительно упрощает работу с иерархиями.
  • Читаемость: Код, написанный с использованием классов, становится более читаемым и проще для понимания, особенно для тех, кто знаком с объектно-ориентированным программированием в других языках.

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