Бесконечное прототипного наследования в JavaScript


Я изучаю прототипное наследование в Javascript, и для моего понимания я пытаюсь использовать его, чтобы отправить процесс в бесконечную рекурсивную цепочку.

Моя идея прототипического наследования состоит в том, что объект (который является функцией) содержит прототипную связь. Любой экземпляр этого объекта указывает на него. Так что если я скажу пример.someproperty он смотрит в цепочку прототипов родительского объекта.

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

 var p = function(){};

 p.prototype = p;
 // I also tried p.prototype = new p();

 var q = new p();

 // and now when I say q.something, it should never be able to find it.
Я хочу знать, почему это не работает и как я могу заставить его войти в бесконечный цикл.
2 4

2 ответа:

Используя более общий стиль:

function P(){};
P.prototype = P;

В ECMA-262 свойствовнутреннего прототипа обозначается через [[Prototype]].

Присвоение другого объекта P. prototype не изменяет P ' s [[Prototype]], поэтому его цепочка наследования остается такой:

P : P[[Prototype]] -> Function.prototype -> Object.prototype -> null

Учитывая, что P и P. прототип указывают на один и тот же объект, цепочка [[prototype]] экземпляра P имеет вид:

p : p[[Prototype]] -> P : P[[Prototype]] -> Function.prototype -> Object.prototype -> null

Так что никакой бесконечной петли.

Без назначение P. прототип, цепочка прототипов p была бы следующей:

p : p[[Prototype]] -> P.prototype -> Object.prototype -> null

Чтобы получить бесконечный цикл, вы можете назначить объекту его собственное свойство __proto__ (открытый способ доступа к [[Prototype]]) в тех браузерах, которые его поддерживают, но я не уверен, что это хорошая идея, Firefox бросает:

"TypeError: cyclic __proto__ value".

Что ж, к вашему первому вопросу:

var p = function(){};

p.prototype = p;
// I also tried p.prototype = new p();

var q = new p();

В первом случае все, что вы делаете при создании экземпляра p, - это устанавливаете прототип для самой функции p, которая является объектом в своем собственном праве (с такими свойствами, как length, prototype, и т.д.). Его фактическим внутренним прототипом является Function.prototype, который, в свою очередь, имеет прототип Object.prototype.

Второй немного отличается-близко, но без сигары. Когда вы присваиваете new p() p.prototype, свойство prototype не установлено тем не менее, таким образом, вы просто получите исходное значение свойства prototype в качестве внутреннего прототипа экземпляра.

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

Даже если бы вам разрешили (браузеры этого не делают), в этом не было бы никакого смысла.

Рассмотрим это:

var a = { b: 1 };
a.__proto__ = a;

Предположим, что это работает, игнорируя тот факт, что это выбрасывает TypeError во всех браузерах (который указан для браузеров в приложении B предстоящей спецификации ES6).

Если бы вы получили доступ к свойству b, Вы бы никогда не поднялись по цепочке прототипов.

Если вы попытаетесь получить доступ к несуществующему свойству, реализация (если она допускает такое) может либо подняться вверх по цепочке прототипов, вернуться к себе рекурсивно, либо признать, что свойство никогда не будет найдено и возвратиться неопределенным.

Конечно, есть ситуация, когда есть несколько вовлеченные объекты:

var a = { x: 1 };
var b = { y: 2 };
b.__proto__ = a;
a.__proto__ = b;
Однако это до смешного глупо и не имеет практической пользы (если это вообще разрешено-это не так).