Перейти к содержимому

new Operator — 4 шага

В одной фразе: оператор new выполняет четыре строго определённых шага — создаёт объект, связывает [[Prototype]], вызывает конструктор, возвращает объект. На собесе просят написать полифил new и объяснить что происходит если конструктор возвращает объект.

// Полифил new — точная реализация 4 шагов спецификации
function myNew(Constructor, ...args) {
// 1. Создать пустой объект
// 2. Установить [[Prototype]] = Constructor.prototype
const obj = Object.create(Constructor.prototype);
// 3. Вызвать конструктор с this = obj
const result = Constructor.apply(obj, args);
// 4. Если конструктор вернул объект — вернуть его, иначе — obj
return (result !== null && typeof result === 'object') ? result : obj;
}
function Point(x, y) { this.x = x; this.y = y; }
const p = myNew(Point, 3, 4);
p instanceof Point; // true
// Шаг 4: конструктор вернул объект → new вернёт его вместо this
function WeirdFactory() {
this.a = 1; // this создан, но...
return { b: 2 }; // возвращаем другой объект — this потерян!
}
const w = new WeirdFactory();
console.log(w.a); // undefined — w это { b: 2 }, а не this
// Возврат примитива из конструктора — игнорируется, new вернёт this
function AlwaysObj() {
this.val = 'ok';
return 42; // число — не объект, игнорируется
}
new AlwaysObj(); // { val: 'ok' }
// new.target: проверить, вызвана ли функция через new
function Guard() {
if (!new.target) {
// Вызов без new: Guard() — предотвращаем тихий баг
throw new TypeError('Guard must be called with new');
}
this.created = true;
}
new Guard(); // OK
// Guard(); // TypeError
// В ES6 class: new.target всегда установлен в конструкторе
// Вызов без new автоматически бросает TypeError (class-specific)
class Strict { constructor() { console.log(new.target.name); } }
// Strict(); // TypeError: Class constructor Strict cannot be invoked without 'new'

Итог: new создаёт объект с [[Prototype]] = Constructor.prototype и вызывает конструктор в контексте этого объекта. Явный return объекта из конструктора подменяет результат new.