React Front-end Инженер

React Front-end Инженер

Роадмап навыков для прокачки

Способы создания объектов

Язык JavaScript (ES5)ОбъектыОбщее

Основная идея

В JavaScript ES5 существует несколько способов создания объектов: литеральная нотация {}, конструктор new Object(), функции-конструкторы с new и метод Object.create(). Каждый подход имеет свои применения.

Ключевые аспекты

  • Литерал объекта {} — самый простой и распространённый способ
  • new Object() — эквивалент литерала, редко используется
  • Функция-конструктор — для создания множества однотипных объектов
  • Object.create() — создание объекта с заданным прототипом

Плюсы и минусы

СпособПлюсыМинусы
Литерал {}Простота, краткостьНе подходит для множества объектов
new Object()ЯвностьИзбыточность, медленнее
КонструкторООП-стиль, переиспользованиеБольше кода
Object.create()Контроль прототипаМенее интуитивен

Частые ошибки на собеседованиях

  • Не знают разницу между {} и new Object() (практически идентичны)
  • Забывают про new при вызове конструктора — this будет window
  • Путают Object.create(null) (объект без прототипа) и {} (прототип Object.prototype)
  • Не понимают, что функция-конструктор — обычная функция, вызванная с new

Введение и проблематика

Объекты — основа JavaScript. Почти всё в языке является объектом или ведёт себя как объект. Понимание различных способов создания объектов важно для выбора правильного подхода в каждой ситуации.

В ES5 основные способы: литерал {}, new Object(), функции-конструкторы и Object.create(). В ES6 добавился синтаксис классов.


Базовая теория

Четыре способа создания объектов

Code Example 1: Какие четыре способа создания объектов продемонстрированы в этом коде?

js
// 1. Литерал объекта
var obj1 = { name: 'Иван' };
 
// 2. Конструктор Object
var obj2 = new Object();
obj2.name = 'Мария';
 
// 3. Функция-конструктор
function Person(name) {
  this.name = name;
}
var obj3 = new Person('Алексей');
 
// 4. Object.create()
var obj4 = Object.create(Object.prototype);
obj4.name = 'Елена';

Практические примеры

1. Литерал объекта {}

Самый простой и распространённый способ.

Code Example 2: Что выведет вызов user.greet()? Почему this внутри метода ссылается на user?

js
// Пустой объект
var empty = {};
 
// Объект со свойствами
var user = {
  name: 'Иван',
  age: 25,
  greet: function() {
    console.log('Привет, ' + this.name);
  }
};
 
user.greet(); // "Привет, Иван"
 
// Вложенные объекты
var company = {
  name: 'IT Corp',
  address: {
    city: 'Москва',
    street: 'Тверская'
  }
};

2. Конструктор new Object()

Функционально эквивалентен литералу, но более громоздкий.

js
var user = new Object();
user.name = 'Мария';
user.age = 30;
 
// Эквивалентно:
var user2 = {};
user2.name = 'Мария';
user2.age = 30;
 
// С начальными значениями (редко используется)
var wrapped = new Object({ x: 1 }); // { x: 1 }
⚠️

new Object() практически не используется в современном коде. Предпочитайте литерал {}.

3. Функция-конструктор

Идеальна для создания множества однотипных объектов.

Code Example 3: Что происходит при вызове new User('Иван', 25)? Что вернёт user1 instanceof User?

js
function User(name, age) {
  // this = {} (неявно создаётся при new)
 
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log('Привет, я ' + this.name);
  };
 
  // return this (неявно)
}
 
var user1 = new User('Иван', 25);
var user2 = new User('Мария', 30);
 
console.log(user1.name); // "Иван"
console.log(user2.name); // "Мария"
 
// Проверка типа
console.log(user1 instanceof User); // true
console.log(user1.constructor === User); // true

Что делает оператор new?

Code Example 4: Какие шаги выполняет оператор new при вызове конструктора?

js
function User(name) {
  this.name = name;
}
 
// new User('Иван') делает следующее:
// 1. Создаёт пустой объект {}
// 2. Устанавливает прототип: {}.__proto__ = User.prototype
// 3. Вызывает User с this = созданный объект
// 4. Возвращает this (или явно возвращённый объект)
🚫

Без new функция-конструктор работает как обычная функция, и this будет window!

Code Example 5: Чем отличается вызов new User('Иван') от вызова User('Иван') без new? Что произойдёт во втором случае?

js
function User(name) {
  this.name = name;
}
 
var user = new User('Иван');
console.log(user.name); // "Иван"
console.log(user instanceof User); // true

4. Object.create()

Создаёт объект с указанным прототипом.

Code Example 6: Как Object.create() создаёт наследование? Что выведет dog.speak()?

js
// Объект с прототипом Object.prototype (как {})
var obj1 = Object.create(Object.prototype);
 
// Объект БЕЗ прототипа
var obj2 = Object.create(null);
console.log(obj2.toString); // undefined — нет прототипа!
 
// Объект с кастомным прототипом
var animal = {
  speak: function() {
    console.log(this.name + ' говорит');
  }
};
 
var dog = Object.create(animal);
dog.name = 'Шарик';
dog.speak(); // "Шарик говорит"

Сравнение способов

СпособПрототипКогда использовать
{}Object.prototypeОдиночные объекты
new Object()Object.prototypeПрактически никогда
КонструкторFunction.prototypeМножество однотипных объектов
Object.create()ЛюбойКонтроль над прототипом

Пограничные кейсы

Object.create(null) — чистый объект

Code Example 7: В чём разница между Object.create(null) и {}? Почему dict['__proto__'] ведёт себя по-разному в двух случаях?

js
var dict = Object.create(null);
 
// Нет унаследованных свойств
console.log(dict.toString); // undefined
console.log(dict.hasOwnProperty); // undefined
 
// Идеально для словарей
dict['__proto__'] = 'значение'; // Безопасно!
console.log(dict['__proto__']); // "значение"
 
// В обычном объекте это проблема:
var regular = {};
regular['__proto__'] = 'значение';
console.log(regular['__proto__']); // [object Object]

Защита от забытого new

Code Example 8: Как этот паттерн защищает от вызова конструктора без new?

js
function User(name) {
  // Проверка на вызов без new
  if (!(this instanceof User)) {
    return new User(name);
  }
  this.name = name;
}
 
// Теперь работает в обоих случаях
var user1 = new User('Иван');
var user2 = User('Мария'); // тоже работает!

Возврат объекта из конструктора

Code Example 9: Что выведут obj.a и obj.b? Что произойдёт, если конструктор вернёт примитив?

js
function Strange() {
  this.a = 1;
  return { b: 2 }; // Явный возврат объекта
}
 
var obj = new Strange();
console.log(obj.a); // undefined
console.log(obj.b); // 2 — возвращённый объект!
 
// Примитивы игнорируются
function Normal() {
  this.a = 1;
  return 42; // Игнорируется
}
 
var obj2 = new Normal();
console.log(obj2.a); // 1

Производительность

js
// Литерал — самый быстрый
var obj1 = { x: 1 };
 
// new Object() — немного медленнее
var obj2 = new Object();
 
// Object.create() — медленнее для простых случаев
var obj3 = Object.create(Object.prototype);

Для создания простых объектов всегда используйте литерал {} — это быстрее и читаемее.


Вопросы интервьюера

Q: Какие способы создания объектов вы знаете?

Литерал {}, new Object(), функции-конструкторы с new, Object.create(). В ES6 также классы.

Q: В чём разница между {} и new Object()?

Функционально идентичны, но литерал короче, быстрее и предпочтительнее.

Q: Что произойдёт, если забыть new при вызове конструктора?

Функция выполнится как обычная, this будет window (или undefined в strict mode), свойства попадут в глобальный объект.

Q: Для чего нужен Object.create(null)?

Создаёт объект без прототипа — идеально для словарей, где ключом может быть "proto" или "hasOwnProperty".


Источники

Code Example 1: Four ways to create objects

❓ Какие четыре способа создания объектов продемонстрированы в этом коде?

js
// 1. Литерал объекта
var obj1 = { name: 'Иван' };
 
// 2. Конструктор Object
var obj2 = new Object();
obj2.name = 'Мария';
 
// 3. Функция-конструктор
function Person(name) {
  this.name = name;
}
var obj3 = new Person('Алексей');
 
// 4. Object.create()
var obj4 = Object.create(Object.prototype);
obj4.name = 'Елена';

Code Example 2: Object literal

❓ Что выведет вызов user.greet()? Почему this внутри метода ссылается на user?

js
var empty = {};
 
var user = {
  name: 'Иван',
  age: 25,
  greet: function() {
    console.log('Привет, ' + this.name);
  }
};
 
user.greet();
 
var company = {
  name: 'IT Corp',
  address: {
    city: 'Москва',
    street: 'Тверская'
  }
};

Code Example 3: Constructor function

❓ Что происходит при вызове new User('Иван', 25)? Что вернёт user1 instanceof User?

js
function User(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log('Привет, я ' + this.name);
  };
}
 
var user1 = new User('Иван', 25);
var user2 = new User('Мария', 30);
 
console.log(user1.name);
console.log(user2.name);
 
console.log(user1 instanceof User);
console.log(user1.constructor === User);

Code Example 4: Operator new

❓ Какие шаги выполняет оператор new при вызове конструктора?

js
function User(name) {
  this.name = name;
}
 
var user = new User('Иван');

Code Example 5: With new vs Without new

❓ Чем отличается вызов new User('Иван') от вызова User('Иван') без new? Что произойдёт во втором случае?

Version A — с new:

js
function User(name) {
  this.name = name;
}
 
var user = new User('Иван');
console.log(user.name);
console.log(user instanceof User);

Version B — без new:

js
function User(name) {
  this.name = name;
}
 
var user = User('Иван');
console.log(user);
console.log(window.name);

Code Example 6: Object.create()

❓ Как Object.create() создаёт наследование? Что выведет dog.speak()?

js
var obj1 = Object.create(Object.prototype);
 
var obj2 = Object.create(null);
console.log(obj2.toString);
 
var animal = {
  speak: function() {
    console.log(this.name + ' говорит');
  }
};
 
var dog = Object.create(animal);
dog.name = 'Шарик';
dog.speak();

Code Example 7: Object.create(null)

❓ В чём разница между Object.create(null) и {}? Почему dict['__proto__'] ведёт себя по-разному в двух случаях?

js
var dict = Object.create(null);
 
console.log(dict.toString);
console.log(dict.hasOwnProperty);
 
dict['__proto__'] = 'значение';
console.log(dict['__proto__']);
 
var regular = {};
regular['__proto__'] = 'значение';
console.log(regular['__proto__']);

Code Example 8: Protection from forgotten new

❓ Как этот паттерн защищает от вызова конструктора без new?

js
function User(name) {
  if (!(this instanceof User)) {
    return new User(name);
  }
  this.name = name;
}
 
var user1 = new User('Иван');
var user2 = User('Мария');

Code Example 9: Return from constructor

❓ Что выведут obj.a и obj.b? Что произойдёт, если конструктор вернёт примитив?

js
function Strange() {
  this.a = 1;
  return { b: 2 };
}
 
var obj = new Strange();
console.log(obj.a);
console.log(obj.b);
 
function Normal() {
  this.a = 1;
  return 42;
}
 
var obj2 = new Normal();
console.log(obj2.a);