Бесконечное прототипного наследования в 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 ответа:
Используя более общий стиль:
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;