Логика прототипов в Javascript

В популярном учебнике learn.javascript.ru в уроке о прототипах есть один хороший пример:

let animal = {
  eats: true
};

function Rabbit(name) {
  this.name = name;
}

Rabbit.prototype = animal;

И казалось бы все нормально, есть Животное и Кролик который наследует от него свойства через Rabbit.prototype, прослеживается логичная иерархия. Свойства же самого Кролика у нас создаются с помощью конструктора Rabbit.

Но почему в встроенных конструкторах используется немного другая логика, менее очевидная. Например при создании const arr = new Array() свои свойства и методы специфичные для массива мы получаем из Array.prototype, а не из самого Array. По аналогии с кроликом, из Array.prototype мы должны получить свойства и методы иерархией выше, т.е свойства объектов.

Понимаю что в данном случае это нужно чтобы "скрыть" встроенные свойства, и отделить от тех которые добавляем мы. Но пока я все еще в замешательстве...


Ответы (1 шт):

Автор решения: OPTIMUS PRIME

В примере скорее всего хотели продемонстрировать, что "так работает".

По аналогии с кроликом, из Array.prototype мы должны получить свойства и методы иерархией выше, т.е свойства объектов

А где в этом примере "иерархией выше"? animal - просто объект, который прямо записывается в прототип кролика.

Когда из объекта вызывается метод:

  1. JS cперва проверит наличие этого метода среди свойств объекта. Если его там нет,
  2. Будет искать метод в .prototype функции-конструктора, с помощью которого был создан этот объект. Соответственно, у созданного объекта есть внутреннее свойство .__proto__ которое ссылается на .prototype своего конструктора. Не путать __proto__ и prototype: Первое - внутри созданных объектов, второе - свойство функции-конструктора.
  3. Если и здесь его не будет... .prototype - сам является объектом, у которого тоже может быть .__proto__ - попробует поискать там, и т.д.

Касаемо Array.prototype...

let arr = ["a", "b", "c"];
  
console.log( arr.hasOwnProperty("0") ); // true
console.log( arr.hasOwnProperty("4") ); // false

Что же произошло?

Хотим вызвать метод hasOwnProperty()

  1. Есть ли внутри arr такой? Нет, там только свойства "0", "1", "2" которые соответственно хранят значения "a", "b", "c" (и свойство length: 3)

  2. Идет к arr.__proto__ оно же, Array.prototype

let arr = ["a", "b", "c"];

console.log( arr.__proto__ === Array.prototype ); // true;

Можно вызвать console.log( Array.prototype ) и убедиться, что там тоже нет метода hasOwnProperty()

Но есть .__proto__ который тоже ссылается на некий объект

let arr = ["a", "b", "c"];

console.log( arr.__proto__ === Array.prototype)
console.log( Array.prototype.__proto__ === Object.prototype) // true
console.log( arr.__proto__.__proto__ === Object.prototype ) // true

И о чудо, находится hasOwnProperty(), который в итоге вызывается в контексте arr.


Это можно представить в виде здания. Ищу метод:

  1. Проверил у себя - не нашел,
  2. Зашел на первый этаж (моя функция-конструктор), открыл дверь (prototype), не нашел метод в комнате,
  3. Через лестницу (__proto__) поднялся на следующий этаж. Открыл дверь там (prototype конструктора, от которого наследуем), и т.п.
  4. Если дошел до крыши, так ничего и не нашел - выдам ошибку ... is not a function
→ Ссылка