Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Работа instanceof и цепочка прототипов (https://javascript.ru/forum/misc/75051-rabota-instanceof-i-cepochka-prototipov.html)

Leonid_ts 29.08.2018 02:02

Работа instanceof и цепочка прототипов
 
Всем привет! Изучаю js, читая Флэнагана и вот я наткнулся на мозговыносящий мне момент, связанный с цепочкой прототипов и работой instanceof.

В подробном руководстве Флэнагана написано "Чтобы вычислить значение выражения o instan­ce­of f, интерпретатор JavaScript определяет значение f.prototype и затем пытается отыскать это значение в цепочке прототипов объекта o. В случае успеха объект o считается экземпляром класса f"

Затем пробую выполнить следующую задачу:
создать объект с, котрый будет наследником объекта b, который является наследником объекта а. При этом эти объекты создаются при помощи соответствующих конструкторов (new A(), new B(), new C()).
получается следующий код:
function A() {
    this.a = 'a';
}

function B() {
    this.b = 'b';
}

function C() {
    this.c = 'c';
}

let a = new A();

B.prototype = a;

let b = new B();

C.prototype = b;

let c = new C()


В результате если ввести в консоль c, то в хроме нам выведет объект. И мое непонимание начинается, когда я смотрю прототипы этого объекта. Хром показывает:
C {c: "c"}
....c: "c"
....__proto__: A
........b: "b"
........__proto__: A
............a: "a"
............__proto__:
................constructor: f A()
................__proto__: Object

Так же если ввести в консоль C.prototype, то мы увидим следующее:
A {b: "b"}
....b: "b"
....__proto__: A
........a: "a"
........__proto__:
............constructor: f A()
............__proto__: Object

Везде в цепочке прототипов указан А и если мы введем в консоль c instanceof C, то резульататом будет true. НО! если мы введем а intanceof C, то результатом будет false. И казалось бы логично, ведь а построен конструктором А. Но ведь в книге сказано
"интерпретатор JavaScript определяет значение f.prototype и затем пытается отыскать это значение в цепочке прототипов объекта o. В случае успеха объект o считается экземпляром класса f"

Так почему a instanceof C будет false, если в консоли явно видно, что прототипом C является прототип А, и а имеет тот же самый прототип, что и С?

Буду благодарен как прямым ответам, так и ссылкам на подбробное разжевывание этого вопроса. На MDN ответа так и не нашел.

P.S. Доп. вопрос: почему если вписать в консоль c мы увидим C {c: "c"}, а если вписать b, то увидим не B {b: "b"}, a A {b: "b"}

Aetae 29.08.2018 02:19

Если утрировать instanceof просто проходит по цепочке прототипов левого аргумента и проверяет на строгое равенство(===) с прототипом правого аргумента.
И это логично в рамках объектного наследования: c создан классом C - наследником от класса A, класс C связан с классом A цепочкой прототипов, потому c instanceof A === true, a же создан классом A - родителем по отношению C, класс A ничего не знает о классе C, он никак с ним не связан, и естественно a instanceof C === false.

А на "доп. вопрос" ответ: хром не угадал. Можешь запостить им баг.)

j0hnik 29.08.2018 02:25

intanceof поверяет принадлежность двигаясь к вершине иерархии пока не дойдет до Object, а не обследует все ветки, если он бы так делал его работа была бы бессмысленна.

Leonid_ts 29.08.2018 13:13

Цитата:

Сообщение от Aetae (Сообщение 493574)
Если утрировать instanceof просто проходит по цепочке прототипов левого аргумента и проверяет на строгое равенство(===) с прототипом правого аргумента.

Спасибо, теперь понятно. Но остался вопрос. Почему хром в свойстве __proto__ в цепочке прототипов объекта с везде пишет A, а не B, затем A? Т.е. почему так

C {c: "c"}
....c: "c"
....__proto__: A
........b: "b"
........__proto__: A
............a: "a"
............__proto__:
................constructor: f A()
................__proto__: Object

а не так
C {c: "c"}
....c: "c"
....__proto__: B
........b: "b"
........__proto__: A
............a: "a"
............__proto__:
................constructor: f A()
................__proto__: Object

Ведь объекту С присвоен прототипом объект b, и только объекту B присвоен прототипом объект а.

Aetae 29.08.2018 16:34

Как сказал выше Rise: ты затер все конструкторы.
В __ptoto__ объекта должна быть ссылка на функцию-конструктор данного объекта(создавшую его). Соответственно делая X.prototype = new Y; заменяешь прототип X по умолчанию (по сути такой {constructor: X, __proto__:Object.prototype }) на объект созданный Y, в котором нет свойства constructor.
Chrome в твоём случае для c соответственно смотрит в __proto__, не видит там constructor, лезет в __proto__.__proto__ смотрит там, не видит, смотрит в __proto__.__proto__.__proto__ и наконец находит первый коструктор, прототип для которого не менялся, сохранив сие свойство: A.

Leonid_ts 29.08.2018 20:19

Aetae,
благодарю! Теперь стало понятно. А можете, если не трудно, привести пример, как было бы правильно организовать подобную цепочку наследования? Спасибо!

Aetae 29.08.2018 20:28

https://learn.javascript.ru/class-in...классах


Часовой пояс GMT +3, время: 15:36.