Вопросы на собеседовании фронтенд-разработчика. Прототипы
[[Prototype]]
У каждого объекта в JavaScript есть внутреннее свойство, в спецификации оно обозначается [[Prototype]]. В нём хранится ссылка на другой объект.
[[Prototype]] помогает искать свойства и методы, которых нет в текущем объекте:
const utils = {
log(message) {
console.log(message)
}
}
const someObj = Object.create(utils)
someObj.log('Hi!')Если запрашиваемое свойство (через операцию [[Get]]) не получается найти в текущем объекте, то будет осуществлён переход по ссылке [[Prototype]] на другой объект и поиск продолжится в нём. Этот процесс будет продолжаться до тех пор, пока свойство не будет найдено или не завершится цепочка [[Prototype]].
По алгоритму выше работает перебор for..in (enumerable учитывается) и проверка с помощью оператора in (enumerable НЕ учитывается).
Object.prototype
Любая нормальная цепочка [[Prototype]] завершается на встроенном объекте Object.prototype.
Object.prototype — это объект, который находится в основе всех встроенных (не являющихся расширениями среды) объектов JavaScript. Содержит различные стандартные методы, используемые в JavaScript.
Свойство prototype у функций
Все функции (кроме стрелочных) по умолчанию имеют открытое и не перечисляемое свойство с названием prototype.
Это свойство указывает на произвольный объект. Объект обычно называют прототипом этой функции, т.к. мы обращаемся к нему по ссылке на свойство func.prototype.
const func = function () {}
const arrowFunc = () => {}
func.prototype // {}
arrowFunc.prototype // undefinedКаждый объект, созданный с помощью вызова функции с оператором new, будет обладать связью со свойством prototype вызванной функции:
const someObj = new func()
Object.getPrototypeOf(someObj) === func.prototype // trueБолее явно можно получить такой же результат с помощью Object.create():
const anotherObj = Object.create(func.prototype)
Object.getPrototypeOf(anotherObj) === func.prototype // trueconstructor
Функция конструктор — любая функция, которая вызывается с помощью new.
Объект prototype у функций по умолчанию имеет открытое неперечисляемое свойство с именем constructor. Это свойство содержит обратную ссылку на вызванную функцию.
function func() {}
func.prototype.constructor === func // trueОбъект, который был создан с помощью new func(), тоже будет обладать свойством constructor (получает по цепочке [[Prototype]]). Свойство будет указывать на функцию создавшую объект.
const someObj = new func()
someObj.constructor === func // trueНаследование
Описанное выше поведение с цепочкой [[Prototype]] называется наследованием на основе прототипов.
Для создания связей между объектами до ES6 использовался Object.create(..). При его использовании будет всегда создаваться новый объект, а не изменяться старый. В ES6+ для этого добавили специальный метод:
Object.setPrototypeOf(
/** кому установить */,
/** [[Prototype]] для установки */
)Пример:
function FirstFunc(name) {}
function SecondFunc() {}
FirstFunc.prototype.logger = function (message) {
console.log(message)
}
Object.setPrototypeOf(SecondFunc.prototype, FirstFunc.prototype);
const secondObj = new SecondFunc()
secondObj.logger('Hi') // HiОператор instanceof
Оператор instanceof используется для проверки принадлежности объекта к свойству .prototype переданной функции. Осуществляет проверку по всей цепочке [[Prototype]].
function SomeFunc() {}
const someObj = new SomeFunc()
someObj instanceof SomeFunc // trueСвойство proto
Реализуемый только в браузерах способ обращения к внутреннему свойству [[Prototype]].
Аналогичный способу получения значения через Object.getPrototypeOf(..).
function SomeFunc() {}
const someObj = new SomeFunc()
someObj.__proto__ === Object.getPrototypeOf(someObj) // true