4.1 KiB
Объектом какого класса является document, можно выяснить так:
//+ run
alert(document); // [object HTMLDocument]
Или так:
//+ run
alert(document.constructor); // function HTMLDocument() { ... }
Итак, document -- объект класса HTMLDocument.
Какое место HTMLDocument занимает в иерархии?
Можно поискать в документации. Но попробуем выяснить это самостоятельно.
Вопрос не такой простой и требует хорошего понимания прототипного наследования.
Вспомним, как оно устроено:
- Методы объекта `document` находятся в `prototype` конструктора, в данном случае -- `HTMLDocument.prototype`.
- У `HTMLDocument.prototype` есть ссылка `__proto__` на прототип-родитель.
- У прототипа-родителя может быть ссылка `__proto__` на его родитель, и так далее.
При поиске свойства в document, если его там нет, оно ищется в document.__proto__, затем в document.__proto__.__proto__ и так далее, пока не найдём, или пока цепочка __proto__ не закончится. Это обычное устройство класса, без наследования.
Нам нужно лишь узнать, что находится в этих самых __proto__.
Строго говоря, там могут быть любые объекты. Вовсе не обязательно, чтобы объектам из цепочки прототипов соответствовали какие-то конструкторы.
Вполне может быть цепочка, где родители -- просто обычные JS-объекты:
document -> HTMLDocument.prototype -> obj1 -> obj2 -> ...
Однако, здесь мы знаем, что наследование -- "на классах", то есть, эти объекты obj1, obj2 являются prototype неких функций-конструкторов:
document -> HTMLDocument.prototype -> F1.prototype -> F2.prototype -> ...
Что стоит на месте F1, F2?
Опять же, если говорить про некие абстрактные объекты, то откуда нам знать, какие функции на них ссылаются через prototype? Ниоткуда. Один объект может быть в prototype хоть у десятка функций.
Но в стандартном прототипном наследовании один объект является prototype ровно у одной функции. Причём при создании функции в её prototype уже есть объект со свойством constructor, которое ссылается обратно на функцию:
F.prototype = { constructor: F }
Это свойство constructor, если конечно его не удалить или не перезаписать нечаянно (чего делать не следует), и позволяет из прототипа узнать соответствующий ему конструктор.
//+ run
// цепочка наследования:
alert(HTMLDocument.prototype.constructor); // function HTMLDocument
alert(HTMLDocument.prototype.__proto__.constructor); // function Document
alert(HTMLDocument.prototype.__proto__.__proto__.constructor); // function Node
При выводе объекта через console.dir(document) в Google Chrome, мы тоже можем, раскрывая __proto__, увидеть эти названия (HTMLDocument, Document, Node).
Браузерная консоль их берёт как раз из свойства constructor.