Почему конструктор прототипа ссылается на самого себя?

От Mozilla-javascript-документы

"Каждый объект имеет частное свойство, которое содержит ссылку на другой объект, называемый его прототипом. Этот объект-прототип имеет собственный прототип, и так далее, пока не будет достигнут объект с нулевым прототипом. По определению null не имеет прототипа и действует как последнее звено в этой цепочке прототипов."

Первый вопрос — я надеюсь, что под «каждый объект содержит прототип» автор имел в виду, что «каждый объект функции» содержит свойство публичныйпрототип, потому что такой объект var myObj = {} не имеет прототипа публичный.

Пожалуйста, посмотрите скриншот консоли ниже — обратите внимание, что общедоступное свойство прототипа (а не приватное __proto__) не существует для объекта, созданного с помощью {} — Почему конструктор прототипа ссылается на самого себя?

Второй вопрос — После прочтения вышеупомянутой литературы, когда я проверял цепочку прототипов простой функции, сначала казалось, что она уходит в бесконечность — но потом я понял, что конструктор прототипа на самом деле ссылается сам на себя. В отличие от того, как это упоминается в Документация Мозиллы, цепочка прототипов здесь, похоже, не заканчивается null в качестве корня.

Я предполагаю, что это было разработано для поддержки наследования на основе прототипов. Но я был бы признателен, если бы это можно было объяснить, как именно эта ссылка на себя в конструкторе прототипа помогает в достижении этого?

Почему конструктор прототипа ссылается на самого себя?

Что касается «подобного объекта var myObj = {}, у которого нет прототипа», этот объект будет иметь Object.prototype в качестве прототипа.

The Witness 13.07.2019 02:49

@Seb .. см. редактирование моего первого вопроса. вар какой-тоОбъект = {}; someObject.prototype.someOtherProperty = "SomeString"; выдает исключение "прототип не определен"

Tintin 13.07.2019 03:37

Чтобы получить доступ к прототипу пример, вы должны использовать Object.getOwnPrototype(someObject).someOtherProperty или в devtools (я думаю, что это не рекомендуется в реальном коде) someObject.__proto__.someOtherProperty или просто someObject.someOtherProperty. prototype является свойством class, а не его экземпляром. Экземпляр по-прежнему связан с прототипом, но к нему можно получить доступ иначе.

The Witness 13.07.2019 12:06
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
3
153
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы хотите найти цепочку прототипов, описанную там:

Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain.

Вы должны посмотреть на свойства __proto__ (которые будут указывать на внутренний прототип исследуемого объекта).

Здесь вы видите, что внутренним прототипом myFunctionObj является Function.prototype, и переход на следующий уровень __proto__ приводит вас к Object.prototype, у которого нет __proto__ (конец цепочки прототипов).

Свойство prototypemyFunctionObj относится к внутреннему прототипу созданные объекты (например, const obj = new myFunctionObj();, а затем obj.__proto__ === myFunctionObj.prototype), а не к внутреннему прототипу самого myFunctionObj.

Обычно только function имеют свойство .prototype, и их .prototype будет ссылаться на внутренний прототип экземпляров, созданных с помощью new. Простые объекты не имеют свойства .prototype (поскольку простые объекты нельзя вызывать для создания чего-либо), но вы все равно можете получить доступ к внутреннему прототипу простого объекта (или чего-либо еще) с помощью Object.getPrototypeOf (или .__proto__):

const obj = {};
console.info(
  obj.__proto__ === Object.prototype,
  Object.getPrototypeOf(obj) === Object.prototype,
);

.prototype.constructor функции — это действительно просто ссылка на функцию.

function foo(){};
console.info(
  foo.prototype.constructor === foo
);

Это не очень полезно, когда у вас уже есть ссылка на конструктор, но это является полезно, когда у вас есть ссылка на экземпляр, но вы не знаете его конструктор - с прототипным наследованием доступ к свойству экземпляра даст вам используемую функцию чтобы построить его:

const bar = (() => {
  function Bar(){}
  const bar = new Bar();
  return bar;
})();

// now Bar is out of scope
// but you can still reference it because you have an instance:
const Bar = bar.constructor;
console.info(Bar);

«Конструктор .prototype.constructor функции действительно является просто ссылкой на функцию». -- Почему так задумано? это был второй вопрос..

Tintin 13.07.2019 01:37

@Tintin Потому что объекты, созданные с использованием этой функции в качестве конструктора, получают этот прототип, и obj.constructor имеет смысл быть ссылкой на конструктор, который использовался для его создания.

Paul 13.07.2019 01:41

@Tintin Свойство .constructor бесполезно, если у вас уже есть ссылка на конструктор, конечно, но может быть полезно, чтобы экземпляры мог ссылаться на него, когда вы еще этого не знаете.

CertainPerformance 13.07.2019 01:42

Спасибо @CertainPerformance. Один вопрос - «Обычно только функции имеют свойство .prototype» ... Не могли бы вы объяснить «обычно» - ?

Tintin 14.07.2019 07:11

Объекты @Tintin могут быть произвольными парами ключ-значение, поэтому можно присвоить свойство prototype объекту, который является нет a function. Это было бы очень запутанно, но это разрешено. const obj = { prototype: { foo: 'foo' }} или myObj.prototype = {};. Это законно, но почти любой код, который выглядит так, скорее всего, заслуживает рефакторинга. В 99% случаев, когда вы видите <something>.prototype, something — это функция, а .prototype будет внутренним прототипом (__proto__) всего, что создается с помощью этой функции.

CertainPerformance 14.07.2019 08:16

Чтобы ответить на ваш второй вопрос:

That prototype object has a prototype of its own...

Я думаю, что проще понять эту концепцию, если вы действительно посмотрите на простой пример нескольких уровней прототипа и на то, как это работает на практике:

function ClassA() {
  this.a = 1;
}
ClassA.prototype.getA = function(){
  return this.a;
};

function ClassB() {
  this.b = 2
}
ClassB.prototype = new ClassA();
ClassB.prototype.getB = function(){
  return this.b;
};

var b = new ClassB();
console.info(b.getA());
> 1
console.info(b.getB());
> 2

Теперь вы заметите, что когда мы определяем класс (функцию), мы расширяем (или добавляем) prototype. Но когда мы смотрим на экземпляр класса (b в моем примере), там нет prototype; это называется __proto__, как уже объяснил @CertainPerformance). Итак, взглянув на цепочку прототипов b, вы увидите следующее:

b.__proto__
> ClassA {a: 1, getB: ƒ}
b.__proto__.__proto__
> {getA: ƒ, constructor: ƒ}
b.__proto__.__proto__.__proto__
> {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
b.__proto__.__proto__.__proto__.__proto__
> null

Поэтому, когда вы вводите b.getB(), движок JavaScript сначала просматривает прямые свойства в объекте b и не видит getB. Затем он смотрит на b.__proto__, находит его и готово.

Для b.getA() он делает то же самое, но не находит его в первом прототипе. Итак, он продолжает b.__proto__.__proto__ и находит его там.

То, что вы видите, отличается. Сначала вы смотрите на prototype функции и видите, что внутри нее есть еще одна функция с именем constructor. А так как constructor также является функцией, внутри нее есть prototype. И так далее, навсегда. Но это — это прототип функции-конструктора, НЕТ — часть цепочки прототипов исходной функции/объекта.

Другие вопросы по теме