Конструкторы и оператор new: полное руководство

Раздел: Объектно-ориентированное программирование -> Использование оператора new

Основы работы с оператором new

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

  1. Создаётся новый пустой объект.
  2. Прототипом этого объекта становится свойство prototype функции-конструктора.
  3. Внутреннее значение this привязывается к новому объекту.
  4. Выполняется тело конструктора: свойства и методы добавляются к this.
  5. Если конструктор не возвращает явно объект, возвращается созданный объект (возврат примитива игнорируется).

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


function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    return `Привет, я ${this.name}`;
  };
}
const user = new Person('Мария', 30);
console.log(user.name); // Мария
console.log(user.greet()); // Привет, я Мария

Js new (оператор new в javascript)

При отсутствии new конструктор выполняется как обычная функция, и this ссылается на глобальный объект (window в браузере, global в Node.js), что приводит к загрязнению глобальной области и некорректным свойствам.

Типичная ошибка: забыть оператор new. Например, const user = Person('Мария', 30); - this внутри функции ссылается на глобальный объект, свойства name и age становятся глобальными, а сама переменная user получает значение undefined. Для защиты используется проверка с instanceof или свойство new.target.

Как защититься от вызова конструктора без new?

Можно внутри конструктора проверить, был ли он вызван через new, и при необходимости автоматически создать экземпляр.


function Car(model) {
  if (!(this instanceof Car)) {
    return new Car(model);
  }
  this.model = model;
}
const car1 = new Car('Tesla');
const car2 = Car('BMW'); // работает как new
console.log(car1.model); // Tesla
console.log(car2.model); // BMW

Проблема: такой подход работает для конструкторов, не возвращающих объект. Если конструктор возвращает объект явно, проверка instanceof может дать ложный результат. Альтернативный способ - использовать new.target (доступен в ES2015):


function Car(model) {
  if (!new.target) {
    throw new Error('Car must be called with new');
    // или return new Car(model);
  }
  this.model = model;
}

Как создать объект без оператора new, используя Object.create?

Метод Object.create позволяет создать объект с заданным прототипом, имитируя работу new без вызова конструктора.


const personProto = {
  greet() {
    return `Привет, я ${this.name}`;
  }
};
function createPerson(name, age) {
  let obj = Object.create(personProto);
  obj.name = name;
  obj.age = age;
  return obj;
}
const user = createPerson('Иван', 25);
console.log(user.greet()); // Привет, я Иван

Этот способ часто используется для наследования через прототипы без конструкторов.

Как работает возврат значения из конструктора?

Если конструктор возвращает примитив (число, строку, булево, null, undefined), то оператор new игнорирует этот возврат и возвращает созданный объект. Если же возвращается объект (включая функции, массивы), то возвращается именно этот объект, а не this.


function Game(title) {
  this.title = title;
  return { custom: true }; // возвращаем другой объект
}
const g = new Game('Doom');
console.log(g.title); // undefined - свойство не установлено
console.log(g.custom); // true

Ошибка: случайный возврат объекта из конструктора приводит к потере всех свойств, добавленных через this. Конструктор не должен возвращать объекты (только примитивы или ничего).

Как использовать class для замены конструктора с new?

Синтаксис class (ES2015) является синтаксическим сахаром для функций-конструкторов и прототипного наследования. Метод constructor вызывается при new.


class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    return `${this.name} издаёт звук`;
  }
}
const dog = new Animal('Собака');
console.log(dog.speak()); // Собака издаёт звук

Классы строго требуют вызова через new; вызов без new вызывает ошибку TypeError.

Расширенные примеры использования оператора new

Пример 1. Конструктор с прототипными методами:

Пример

function Book(title, author) {
  this.title = title;
  this.author = author;
}
Book.prototype.getInfo = function() {
  return `${this.title} - ${this.author}`;
};
const myBook = new Book('1984', 'Джордж Оруэлл');
console.log(myBook.getInfo());

Результат:

1984 - Джордж Оруэлл

Пример 2. Наследование через prototype и new:

Пример

function Vehicle(type) {
  this.type = type;
}
Vehicle.prototype.move = function() {
  return `Транспорт ${this.type} движется`;
};
function Car(brand) {
  Vehicle.call(this, 'автомобиль');
  this.brand = brand;
}
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.constructor = Car;
Car.prototype.honk = function() {
  return `${this.brand} сигналит`;
};
const myCar = new Car('Toyota');
console.log(myCar.move());
console.log(myCar.honk());

Результат:

Транспорт автомобиль движется
Toyota сигналит

Пример 3. Оператор new со встроенными конструкторами (Array, Date, RegExp):

Пример

const arr = new Array(3); // пустой массив длины 3
console.log(arr.length);
const now = new Date();
console.log(now.toLocaleDateString());
const regex = new RegExp('\\d+', 'g');
console.log(regex.test('abc123'));

Результат (дата может отличаться):

3
01.01.2025
true

Пример 4. Использование new.target в строгом режиме:

Пример

'use strict';
function StrictConstr() {
  console.log(new.target);
}
const s = new StrictConstr(); // [Function: StrictConstr]
// вызов без new в строгом режиме приведёт к TypeError

Вывод:

[Function: StrictConstr]

Пример 5. Абстрактный конструктор через new.target:

Пример

function AbstractClass() {
  if (new.target === AbstractClass) {
    throw new Error('Нельзя создавать экземпляр абстрактного класса');
  }
  // инициализация для наследников
}
function Derived() {
  AbstractClass.call(this);
}
Derived.prototype = Object.create(AbstractClass.prototype);
try {
  const obj = new AbstractClass();
} catch (e) {
  console.log(e.message);
}
const d = new Derived();
console.log(d instanceof AbstractClass); // true

Результат:

Нельзя создавать экземпляр абстрактного класса
true

Пример 6. Фабрика одиночек (Singleton) с перезаписью конструктора:

Пример

function Singleton() {
  const instance = this;
  Singleton = function() {
    return instance;
  };
}
const a = new Singleton();
const b = new Singleton();
console.log(a === b); // true

Результат:

true

Пример 7. Symbol.species и new в подклассах:

Пример

class MyArray extends Array {
  static get [Symbol.species]() { return Array; }
}
const myArr = new MyArray(1, 2, 3);
const mapped = myArr.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true

Результат:

false
true

Оператор new в JavaScript - comments

En
Js new (javascript)