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
.