Понимание наследования прототипов
Я нарисовал следующую картину, демонстрирующую, как объекты наследуются (конструкторы функций отмечены как синие, объекты, созданные из этих конструкторов, помечены как зеленые):
![введите описание изображения здесь]()
Вот код, создающий такую иерархию:
function Figure() {}
function Rect() {}
Rect.prototype = new Figure();
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = new Figure();
function Circle() {}
Circle.prototype = new Ellipse();
Теперь я хочу проверить, наследуется ли new Square()
от Rect
, поэтому я ожидаю, что механизм JavaScript проверяет его:
var s = new Square();
s instanceof Rect // ?
s.__proto__ === Rect.prototype // false
new Rect() new Figure()
s.__proto__.__proto__ === Rect.prototype // true
new Figure() new Figure()
Итак s instanceof Rect
должен возвращать true
. Это ожидается и на самом деле возвращается, если я запускаю код. Но затем я хочу проверить, наследуется ли new Circle()
от Rect
, поэтому я следую той же логике:
var c = new Circle();
c instanceof Rect // ?
c.__proto__ === Rect.prototype // false
new Ellipse() new Figure()
c.__proto__.__proto__ === Rect.prototype // true
new Figure() new Figure()
Итак, использование этой логики проверки c instanceof Rect
должно возвращать true
, но если я действительно запускаю код, c instanceof Rect
возвращает false. Неужели я не понимаю механизм оператора instanceof
?
Ответы
Ответ 1
Ваша логика правильная, но исходные предположения были немного неправильными. Можно эмулировать регулярное классовое наследование с прототипами.
Чтобы воспроизвести структуру, которую вы нарисовали, я создал следующий код:
function Figure() {}
function Rect() {}
function Square() {}
function Ellipse() {}
function Circle() {}
Ellipse.prototype = Rect.prototype = new Figure();
Square.prototype = new Rect();
Circle.prototype = new Ellipse();
console.log("is Figure: " + (new Circle() instanceof Figure));
console.log("is Ellipse: " + (new Circle() instanceof Ellipse));
console.log("is Rect: " + (new Circle() instanceof Rect));
Ответ 2
Учитывая пример кода в вашем вопросе, c.__proto__.__proto__ === Rect.prototype
возвращает false
. new Figure
вызывается дважды и создает два разных экземпляра Figure
.
Различные экземпляры объектов не равны.
function Figure() {}
function Rect() {}
Rect.prototype = new Figure();
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = new Figure();
function Circle() {}
Circle.prototype = new Ellipse();
var c = new Circle();
console.log('c instanceof Rect:', c instanceof Rect);
console.log('c.__proto__ === Rect.prototype', c.__proto__ === Rect.prototype);
console.log('c.__proto__.__proto__ === Rect.prototype', c.__proto__.__proto__ === Rect.prototype);
Ответ 3
Тот факт, что круги и квадраты имеют рисунок в своих цепочках прототипов, означает, что c instanceof Figure
и s instanceof Figure
являются истинными, но каждый из них имеет свой собственный рисунок, потому что new Figure()
был вызван дважды. Обратите внимание, что new Figure() != new Figure()
, поскольку объекты в Javascript никогда не равны другим объектам. Ниже приведена диаграмма, показывающая, что происходит в вашем коде выше. Вы можете видеть, что в кругах и квадратах каждый имеет отдельный рисунок в своих цепочках прототипов:
![введите описание изображения здесь]()
Обратите внимание, что вы можете немного изменить свой код, чтобы повторно использовать одну фигуру в качестве прототипа как для Rect, так и для Ellipse, что будет соответствовать диаграмме в вашем исходном сообщении и приведет к точному поведению, которое вы ожидаете увидеть:
function Figure() {}
var f = new Figure();
function Rect() {}
Rect.prototype = f;
function Square() {}
Square.prototype = new Rect();
function Ellipse() {}
Ellipse.prototype = f;
function Circle() {}
Circle.prototype = new Ellipse();
console.log( (new Circle) instanceof Rect ); // true