Avatar ·

Что делает ключевое слово `new` в JavaScript? Объясните на примерах

Всем привет! Я только начал изучать JavaScript и наткнулся на ключевое слово `new`. Честно говоря, я запутался. Вроде бы я понимаю, что оно связано с созданием объектов, но как именно оно работает — не совсем ясно. Например, я вижу такой код: ```javascript function Person(name) { this.name = name; this.sayHello = function() { console.log('Привет, меня зовут ' + this.name); }; } const user = new Person('Анна'); user.sayHello(); // Привет, меня зовут Анна ``` Но если я напишу без `new`: ```javascript const user = Person('Анна'); console.log(user); // undefined ``` Почему так происходит? Что именно делает `new` внутри? Я слышал, что он как-то связывает `this`, но не понимаю деталей. Также я видел, что в некоторых учебниках пишут функции-конструкторы с заглавной буквы, но не всегда. И ещё я слышал про `prototype` — это как-то связано с `new`? Объясните, пожалуйста, пошагово, что происходит, когда мы пишем `new SomeFunction()`. И есть ли альтернативы `new` в современном JavaScript? Буду благодарен за простые примеры и наглядное объяснение! <<>>

Как работает ключевое слово new: пошаговое объяснение

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

  1. Создаётся новый пустой объект — простой объект {}.
  2. К этому объекту привязывается прототип — устанавливается связь с FunctionName.prototype, чтобы объект наследовал методы.
  3. Вызывается функция с this, указывающим на новый объект — внутри функции вы можете добавлять свойства через this.property = value.
  4. Возвращается созданный объект (если функция явно не возвращает другой объект).

Вот как это выглядит на практике:

function Person(name) {
  // Шаг 1: создаётся {} (неявно)
  // Шаг 2: {}.__proto__ = Person.prototype (неявно)
  // Шаг 3: this = {} (неявно)
  
  this.name = name; // теперь {} имеет свойство name
  this.sayHello = function() {
    console.log('Привет, меня зовут ' + this.name);
  };
  
  // Шаг 4: return this; (неявно)
}

const user = new Person('Анна');
console.log(user.name); // "Анна"
user.sayHello(); // "Привет, меня зовут Анна"

Почему без new не работает?

Если вызвать Person('Анна') без new, то:

  • this будет указывать на глобальный объект (window в браузере или global в Node.js)
  • Свойство name и функция sayHello будут добавлены к глобальному объекту
  • Сама функция вернёт undefined, так как нет явного return

Прототипы и new

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

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

// Добавляем метод в прототип
Animal.prototype.say = function() {
  console.log('Я — ' + this.type);
};

const cat = new Animal('кошка');
const dog = new Animal('собака');

cat.say(); // "Я — кошка"
dog.say(); // "Я — собака"

// Это один и тот же метод!
console.log(cat.say === dog.say); // true

Современная альтернатива: классы (ES6+)

С появлением ES6 (2015) появился синтаксис class, который делает то же самое, но выглядит понятнее:

class Person {
  constructor(name) {
    this.name = name;
  }
  
  sayHello() {
    console.log('Привет, меня зовут ' + this.name);
  }
}

const user = new Person('Анна');
user.sayHello(); // "Привет, меня зовут Анна"

Под капотом классы — это те же функции-конструкторы с new. Но синтаксис class считается более читаемым и безопасным (например, если забыть new, будет ошибка).

Важные моменты

  • Именование: функции-конструкторы принято называть с заглавной буквы (PascalCase) — это соглашение, чтобы отличать их от обычных функций.
  • Возврат объекта: если конструктор явно возвращает объект, new вернёт этот объект, а не this.
  • Стрелочные функции: их нельзя использовать как конструкторы — new с ними вызовет ошибку.

В итоге: new — это способ сказать JavaScript: «Создай новый объект, привяжи к нему прототип и передай его как this в функцию». Без new вы просто вызываете функцию, и this теряется.

<<>>

Альтернативный взгляд: фабричные функции и Object.create()

Хотя new и классы — стандартный способ создания объектов в JS, существуют альтернативы, которые могут быть удобнее в некоторых ситуациях.

Фабричная функция (Factory Function)

Это обычная функция, которая возвращает новый объект без использования new:

function createPerson(name) {
  return {
    name: name,
    sayHello() {
      console.log('Привет, меня зовут ' + this.name);
    }
  };
}

const user = createPerson('Анна');
user.sayHello(); // "Привет, меня зовут Анна"

Плюсы: не нужно помнить про new, нет риска испортить глобальный объект. Минус: каждый объект получает свою копию метода (больше памяти).

Object.create()

Этот метод создаёт объект с указанным прототипом:

const personProto = {
  sayHello() {
    console.log('Привет, меня зовут ' + this.name);
  }
};

function createPerson(name) {
  const obj = Object.create(personProto);
  obj.name = name;
  return obj;
}

const user = createPerson('Анна');
user.sayHello(); // "Привет, меня зовут Анна"

Object.create() даёт полный контроль над прототипом, но требует больше кода. Обычно на практике используют либо классы (для сложных иерархий), либо фабричные функции (для простых объектов). Выбирайте то, что понятнее вашей команде!