this — это только что созданный объект в вызове конструктора.

Что значит «только что созданный»? Ключевое слово new запускает под капотом четырёхшаговый ритуал: движок создаёт новый пустой объект, назначает его как this внутри функции, привязывает .prototype-цепочку, а после выполнения тела функции возвращает этот объект наружу — даже если функция не написала return. Ты пишешь в тело функции this.name = 'Аня', но по факту заполняешь свойства нового объекта, который потом получишь на выходе.

Базовый пример

function Article(title, author) {
  // this — только что созданный пустой объект
  this.title = title;
  this.author = author;
  this.publishedAt = new Date();
  // return не нужен — this вернётся автоматически
}

const post = new Article('Разбор this', 'Аня');
console.log(post.title);        // => 'Разбор this'
console.log(post.author);       // => 'Аня'
console.log(post instanceof Article);   // => true

Функции, предназначенные для вызова через new, по соглашению называют с большой буквы (Article, Book, User) — это визуальный сигнал читателю, что функция — конструктор. Соглашение не enforced, но настолько устойчивое, что становится частью языка.

Классы ES6

С 2015 года есть более удобный синтаксис — class. Под капотом это тот же new-вызов с тем же this-поведением, но с более чистым синтаксисом:

class Article {
  constructor(title, author) {
    this.title = title;
    this.author = author;
    this.publishedAt = new Date();
  }

  summary() {
    return `${this.title} by ${this.author}`;
  }
}

const post = new Article('Разбор this', 'Аня');
post.summary();   // => 'Разбор this by Аня'

Внутри тела класса — в constructor и всех методах — строгий режим включён автоматически. this в конструкторе указывает на создаваемый экземпляр; в методах — на объект, у которого метод вызвали (обычное правило метода).

Явный return в конструкторе

Обычный конструктор ничего не возвращает — this автоматически становится результатом new. Но если явно вернуть объект, он и станет результатом:

function StrangeConstructor() {
  this.foo = 'bar';
  return { hello: 'world' };   // возвращаем ДРУГОЙ объект
}

const x = new StrangeConstructor();
console.log(x.foo);       // => undefined
console.log(x.hello);     // => 'world'

Если явно вернуть примитив (число, строку, boolean, null), он игнорируется — результатом всё равно будет this:

function TrickyConstructor() {
  this.foo = 'bar';
  return 42;               // примитив — игнорируется
}

const x = new TrickyConstructor();
console.log(x.foo);        // => 'bar'
console.log(x === 42);     // => false

Это редко используется намеренно, но паттерн «конструктор возвращает другой объект» применяется в некоторых старых библиотеках для реализации abstract factory. В современном коде для этого пишут именно factory-функцию, а не конструктор с трюком.

Конструктор vs factory-функция

Альтернативный способ создания объектов — factory-функция: обычная функция, возвращающая объект без использования new:

// конструктор с this
class Article {
  constructor(title, author) {
    this.title = title;
    this.author = author;
  }
}

// factory-функция без this
function createArticle(title, author) {
  return {
    title,
    author,
    summary() {
      return `${title} by ${author}`;
    }
  };
}

const a = new Article('X', 'Y');
const b = createArticle('X', 'Y');

Обе версии решают одну и ту же задачу — создать объект с полями и методами. Разница — в наличии this, наследовании (у класса есть .prototype, у factory нет), поведении при instanceof (класс поддерживает, factory нет).

Factory-функции проще — в них нет this-ловушек и не нужен new. В функциональном стиле программирования часто предпочитают их. Классы дают более компактный синтаксис для сложных иерархий с наследованием и оптимизируются движками эффективнее для тысяч экземпляров.

Если забыть new

Главная опасность конструктора — вызвать его без new. Это тихо «портит» глобальный объект в нестрогом режиме, или падает с TypeError в строгом. Разбор с примерами и защитными паттернами — в следующей подглаве.