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 вернёт его вместо thisfunction WeirdFactory() { this.a = 1; // this создан, но... return { b: 2 }; // возвращаем другой объект — this потерян!}const w = new WeirdFactory();console.log(w.a); // undefined — w это { b: 2 }, а не this
// Возврат примитива из конструктора — игнорируется, new вернёт thisfunction AlwaysObj() { this.val = 'ok'; return 42; // число — не объект, игнорируется}new AlwaysObj(); // { val: 'ok' }// new.target: проверить, вызвана ли функция через newfunction 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.