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 в строгом. Разбор с примерами и защитными паттернами — в следующей подглаве.