Этот вопрос проверяет понимание особого поведения функций-конструкторов при возврате объектов и различий с возвратом примитивов.
Если функция-конструктор возвращает объект, то возвращается именно этот объект, а не автоматически созданный через this. Возвращаемый объект полностью заменяет объект, на который ссылается this. Это позволяет создавать фабричные методы и контролировать процесс создания объектов.
Когда функция-конструктор возвращает объект, это кардинально меняет стандартное поведение.
Возвращаемый объект заменяет объект, созданный оператором new:
javascript
function Person(name) {
this.name = name; // Это свойство будет потеряно
// Возвращаемый объект заменяет созданный
return { customName: 'Кастомное имя' };
}
const person = new Person('Иван');
console.log(person); // { customName: 'Кастомное имя' }
console.log(person.name); // undefined
console.log(person instanceof Person); // falseРазница между возвратом объекта и примитива:
javascript
function NormalConstructor() {
this.property = 'значение';
// Не возвращаем ничего (или возвращаем примитив)
}
function ObjectReturningConstructor() {
this.property = 'значение';
return { customProperty: 'кастомное значение' };
}
const normal = new NormalConstructor();
const custom = new ObjectReturningConstructor();
console.log(normal.property); // "значение"
console.log(custom.property); // undefined
console.log(custom.customProperty); // "кастомное значение"Это поведение используется в различных паттернах:
javascript
function CreateUser(type) {
if (type === 'admin') {
return { role: 'admin', permissions: ['read', 'write', 'delete'] };
} else {
return { role: 'user', permissions: ['read'] };
}
}
const admin = new CreateUser('admin');
const user = new CreateUser('user');javascript
function Logger(name) {
// Если экземпляр уже существует, возвращаем его
if (Logger.instances[name]) {
return Logger.instances[name];
}
this.name = name;
Logger.instances[name] = this;
}
Logger.instances = {};
const logger1 = new Logger('app');
const logger2 = new Logger('app');
console.log(logger1 === logger2); // true - тот же объектjavascript
function Observable(target) {
const observers = [];
return {
subscribe: function(observer) {
observers.push(observer);
},
notify: function(data) {
observers.forEach(observer => observer(data));
},
// Сохраняем оригинальный target
target: target
};
}
const observable = new Observable({ data: 'test' });Возврат объектов из конструкторов может быть неочевидным:
javascript
function ConfusingConstructor() {
this.expected = 'ожидаемое свойство';
return { unexpected: 'неожиданное свойство' };
}
const obj = new ConfusingConstructor();
// Разработчик может ожидать obj.expected, но получит obj.unexpectedВместо возврата объектов из конструкторов лучше использовать фабричные функции:
javascript
// Более понятная альтернатива
function createUser(type) {
if (type === 'admin') {
return { role: 'admin', permissions: ['read', 'write', 'delete'] };
} else {
return { role: 'user', permissions: ['read'] };
}
}
// Вызывается без new
const admin = createUser('admin');Вывод: При возврате объекта из функции-конструктора возвращается именно этот объект, а не автоматически созданный. Это мощная возможность, но ее следует использовать осознанно, так как она нарушает стандартное ожидание поведения конструкторов.