Angular Front-end Инженер

Angular Front-end Инженер

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

Получение и установка прототипа

Язык JavaScript (ES5)Прототипы и наследованиеОсновное

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

В ES5 для работы с прототипом объекта используются методы Object.getPrototypeOf() для чтения и Object.setPrototypeOf() (ES6) или __proto__ для записи. Стандартный способ чтения — Object.getPrototypeOf().

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

  • Object.getPrototypeOf(obj) — возвращает прототип объекта (ES5, стандарт)
  • Object.setPrototypeOf(obj, proto) — устанавливает прототип (ES6)
  • obj.proto — геттер/сеттер для прототипа (нестандартный, но широко поддерживается)
  • obj.isPrototypeOf(other) — проверяет, является ли obj прототипом other

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

МетодПлюсыМинусы
getPrototypeOf()Стандарт ES5, надёжныйТолько чтение
setPrototypeOf()Стандарт ES6Медленный, не в ES5
protoПростой синтаксисНестандартный, медленный

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

  • Путают __proto__ (ссылка на прототип) и prototype (свойство функции)
  • Не знают, что изменение прототипа на лету — очень медленная операция
  • Забывают, что Object.getPrototypeOf(Object.prototype) === null
  • Путают isPrototypeOf() (метод объекта) и instanceof (оператор для конструктора)

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

Для работы с цепочкой прототипов необходимо уметь получать и изменять прототип объекта. В ES5 стандартизирован метод для чтения, а изменение прототипа возможно через нестандартный __proto__ или ES6 метод.

Object.getPrototypeOf() — единственный стандартный способ получения прототипа в ES5.


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

Способы работы с прототипом

Code Example 1: Какие способы получения и установки прототипа объекта существуют в JavaScript?

js
var parent = { x: 1 };
var child = Object.create(parent);
 
// Получение прототипа (ES5)
Object.getPrototypeOf(child); // parent
 
// Установка прототипа (ES6)
Object.setPrototypeOf(child, newParent);
 
// Нестандартный способ (работает почти везде)
child.__proto__; // получение
child.__proto__ = newParent; // установка

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

Object.getPrototypeOf()

Code Example 2: Что вернёт Object.getPrototypeOf(rabbit)? Чему равен Object.getPrototypeOf(Object.prototype)?

js
var animal = {
  eats: true
};
 
var rabbit = Object.create(animal);
 
// Получаем прототип
var proto = Object.getPrototypeOf(rabbit);
console.log(proto === animal); // true
console.log(proto.eats);       // true
 
// Цепочка прототипов
console.log(Object.getPrototypeOf(animal) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype) === null);    // true

Проверка цепочки с isPrototypeOf()

Code Example 3: Что выведут все console.log? Проверяет ли isPrototypeOf всю цепочку прототипов?

js
var animal = { eats: true };
var rabbit = Object.create(animal);
var whiteRabbit = Object.create(rabbit);
 
// isPrototypeOf проверяет всю цепочку
console.log(animal.isPrototypeOf(rabbit));      // true
console.log(animal.isPrototypeOf(whiteRabbit)); // true
console.log(rabbit.isPrototypeOf(whiteRabbit)); // true
 
console.log(Object.prototype.isPrototypeOf(whiteRabbit)); // true

Использование proto

⚠️

__proto__ — нестандартное свойство. Используйте Object.getPrototypeOf() для чтения и избегайте изменения прототипа.

Code Example 4: Что выведет rabbit.eats после установки rabbit.__proto__ = animal?

js
var animal = { eats: true };
var rabbit = { jumps: true };
 
// Получение (аналог Object.getPrototypeOf)
console.log(rabbit.__proto__ === Object.prototype); // true
 
// Установка
rabbit.__proto__ = animal;
console.log(rabbit.eats); // true
 
// Это работает, но медленно и не рекомендуется

Сравнение методов

Code Example 5: Чем отличаются три способа работы с прототипом? Какой из них стандартный в ES5?

js
var obj = { x: 1 };
var child = Object.create(obj);
 
// Стандартный метод ES5
var proto = Object.getPrototypeOf(child);
console.log(proto === obj); // true
 
// Работает с любым объектом
console.log(Object.getPrototypeOf([]) === Array.prototype); // true
console.log(Object.getPrototypeOf(function(){}) === Function.prototype); // true
МетодНазначениеES5Рекомендуется
getPrototypeOf()ПолучениеДаДа
setPrototypeOf()УстановкаНет (ES6)Осторожно
protoОбаНетНет
isPrototypeOf()ПроверкаДаДа

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

Прототип примитивов

Code Example 6: Как получить прототип примитивного значения? Что произойдёт при прямом вызове Object.getPrototypeOf на примитиве?

js
// Примитивы не имеют __proto__, но можно получить прототип обёртки
console.log(Object.getPrototypeOf(Object("строка")) === String.prototype); // true
console.log(Object.getPrototypeOf(Object(42)) === Number.prototype);       // true
 
// Напрямую — ошибка в ES5 strict
// Object.getPrototypeOf("строка"); // TypeError в ES5, String.prototype в ES6

Object.create(null)

Code Example 7: Что вернёт Object.getPrototypeOf(noProto)? Почему noProto.__proto__ возвращает undefined?

js
var noProto = Object.create(null);
 
console.log(Object.getPrototypeOf(noProto)); // null
console.log(noProto.__proto__); // undefined (нет геттера)
 
// У такого объекта нет isPrototypeOf
// noProto.isPrototypeOf({}); // TypeError

Изменение прототипа — медленно!

js
var obj = { x: 1 };
 
// ❌ Плохо — очень медленная операция
obj.__proto__ = { y: 2 };
 
// ❌ Ещё хуже — делать это в цикле
for (var i = 0; i < 1000; i++) {
  obj.__proto__ = { z: i }; // Катастрофа для производительности
}
🚫

Изменение прототипа после создания объекта — очень медленная операция. Движок JS оптимизирует объекты на основе их прототипа, и изменение ломает эти оптимизации.


isPrototypeOf vs instanceof

Code Example 8: В чём разница между isPrototypeOf и instanceof? Почему obj instanceof proto вызовет ошибку?

js
function Animal() {}
var rabbit = new Animal();
 
// instanceof проверяет Constructor.prototype
console.log(rabbit instanceof Animal); // true
 
// isPrototypeOf проверяет любой объект в цепочке
console.log(Animal.prototype.isPrototypeOf(rabbit)); // true
 
// Разница
var proto = { x: 1 };
var obj = Object.create(proto);
 
console.log(proto.isPrototypeOf(obj)); // true
// obj instanceof proto; // TypeError — proto не функция

Получение всей цепочки прототипов

Code Example 9: Что вернёт getPrototypeChain для массива [1, 2, 3]? А для экземпляра new MyClass()?

js
function getPrototypeChain(obj) {
  var chain = [];
  var current = Object.getPrototypeOf(obj);
 
  while (current !== null) {
    chain.push(current);
    current = Object.getPrototypeOf(current);
  }
 
  return chain;
}
 
var arr = [1, 2, 3];
console.log(getPrototypeChain(arr));
// [Array.prototype, Object.prototype]
 
function MyClass() {}
var instance = new MyClass();
console.log(getPrototypeChain(instance));
// [MyClass.prototype, Object.prototype]

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

Q: Как получить прототип объекта?

Стандартный способ — Object.getPrototypeOf(obj). Нестандартный — obj.__proto__.

Q: Можно ли изменить прототип объекта после создания?

Да, через __proto__ или Object.setPrototypeOf() (ES6), но это сильно замедляет работу и не рекомендуется.

Q: В чём разница между isPrototypeOf и instanceof?

isPrototypeOf — метод объекта, проверяет наличие в цепочке. instanceof — оператор, работает с функциями-конструкторами.

Q: Что вернёт Object.getPrototypeOf(Object.prototype)?

null — это конец цепочки прототипов.


Источники

Code Example 1: Ways to work with prototype

❓ Какие способы получения и установки прототипа объекта существуют в JavaScript?

js
var parent = { x: 1 };
var child = Object.create(parent);
 
// Получение прототипа
Object.getPrototypeOf(child);
 
// Установка прототипа
Object.setPrototypeOf(child, newParent);
 
// Нестандартный способ
child.__proto__;
child.__proto__ = newParent;

Code Example 2: Object.getPrototypeOf()

❓ Что вернёт Object.getPrototypeOf(rabbit)? Чему равен Object.getPrototypeOf(Object.prototype)?

js
var animal = {
  eats: true
};
 
var rabbit = Object.create(animal);
 
var proto = Object.getPrototypeOf(rabbit);
console.log(proto === animal);
console.log(proto.eats);
 
console.log(Object.getPrototypeOf(animal) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);

Code Example 3: isPrototypeOf()

❓ Что выведут все console.log? Проверяет ли isPrototypeOf всю цепочку прототипов?

js
var animal = { eats: true };
var rabbit = Object.create(animal);
var whiteRabbit = Object.create(rabbit);
 
console.log(animal.isPrototypeOf(rabbit));
console.log(animal.isPrototypeOf(whiteRabbit));
console.log(rabbit.isPrototypeOf(whiteRabbit));
 
console.log(Object.prototype.isPrototypeOf(whiteRabbit));

Code Example 4: Using __proto__

❓ Что выведет rabbit.eats после установки rabbit.__proto__ = animal?

js
var animal = { eats: true };
var rabbit = { jumps: true };
 
console.log(rabbit.__proto__ === Object.prototype);
 
rabbit.__proto__ = animal;
console.log(rabbit.eats);

Code Example 5: getPrototypeOf vs __proto__ vs isPrototypeOf

❓ Чем отличаются три способа работы с прототипом? Какой из них стандартный в ES5?

getPrototypeOf:

js
var obj = { x: 1 };
var child = Object.create(obj);
 
var proto = Object.getPrototypeOf(child);
console.log(proto === obj);
 
console.log(Object.getPrototypeOf([]) === Array.prototype);
console.log(Object.getPrototypeOf(function(){}) === Function.prototype);

__proto__:

js
var obj = { x: 1 };
var child = Object.create(obj);
 
console.log(child.__proto__ === obj);
 
child.__proto__ = { y: 2 };
console.log(child.y);
console.log(child.x);

isPrototypeOf:

js
var animal = { eats: true };
var rabbit = Object.create(animal);
 
console.log(animal.isPrototypeOf(rabbit));
 
console.log(Object.prototype.isPrototypeOf(rabbit));
console.log(Object.prototype.isPrototypeOf(animal));

Code Example 6: Prototype of primitives

❓ Как получить прототип примитивного значения? Что произойдёт при прямом вызове Object.getPrototypeOf на примитиве?

js
console.log(Object.getPrototypeOf(Object("строка")) === String.prototype);
console.log(Object.getPrototypeOf(Object(42)) === Number.prototype);

Code Example 7: Object.create(null) prototype

❓ Что вернёт Object.getPrototypeOf(noProto)? Почему noProto.__proto__ возвращает undefined?

js
var noProto = Object.create(null);
 
console.log(Object.getPrototypeOf(noProto));
console.log(noProto.__proto__);

Code Example 8: isPrototypeOf vs instanceof

❓ В чём разница между isPrototypeOf и instanceof? Почему obj instanceof proto вызовет ошибку?

js
function Animal() {}
var rabbit = new Animal();
 
console.log(rabbit instanceof Animal);
 
console.log(Animal.prototype.isPrototypeOf(rabbit));
 
var proto = { x: 1 };
var obj = Object.create(proto);
 
console.log(proto.isPrototypeOf(obj));

Code Example 9: Getting the entire prototype chain

❓ Что вернёт getPrototypeChain для массива [1, 2, 3]? А для экземпляра new MyClass()?

js
function getPrototypeChain(obj) {
  var chain = [];
  var current = Object.getPrototypeOf(obj);
 
  while (current !== null) {
    chain.push(current);
    current = Object.getPrototypeOf(current);
  }
 
  return chain;
}
 
var arr = [1, 2, 3];
console.log(getPrototypeChain(arr));
 
function MyClass() {}
var instance = new MyClass();
console.log(getPrototypeChain(instance));