4

I'm learning prototypal inheritance in Javascript, and for my understanding I'm trying to use it to send the process into infinite recursive chaining.

My idea of prototypal inheritance is that an object (which is a function) holds prototype link. Any instance of that object points to it. So if I say instance.someproperty it looks into the prototype chain of the parent object.

Assuming this, If I just point function prototype list to itself, it should go into infinite loop when object tries to access some property.

 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.

I want to know why this doesn't work and how can I make it to go into infinite loop.

sublime
  • 4,013
  • 9
  • 53
  • 92
  • The prototype function itself has nothing to do with property lookup. – Pointy Apr 17 '14 at 23:36
  • 1
    for learning purpose? Is everything you do in your life is useful to you? – sublime Apr 17 '14 at 23:58
  • @jfriend It's okay to not be a hacker. But I wouldn't knock people for having the inclination. – Erik Reppen Apr 18 '14 at 01:49
  • @jfriend00 - By "hacker" I'm going on the more classic definition of someone who takes an axe to things to understand how they work. Prototype is more of a surrogate lookup mechanism than a true inheritance mechanic. Understanding that has played key role in my everyday-use/implementation of it when it comes up. It's not about breaking stuff but rather understanding why it doesn't break. – Erik Reppen Apr 18 '14 at 01:56
  • I think what jfriend meant is that you might teach him a new trick by explaining a valid reason as to why you would want this. Learning purposes is a valid reason but not a practical one. I ask all the time why this or that hoping I missed something and maybe learn something new, its not to insult but to clarify. In his question as to why he also mentions the obvious disadvantage of creating such a loop – HMR Apr 18 '14 at 02:01
  • 1
    I think he asked why you'd want the chicken to cross the road when the real question was "Holy crap! How did it end up getting to the other side?" – Erik Reppen Apr 18 '14 at 02:36
  • @jfriend00 - man so much of negativity. people here are just interested in learning, if you cannot add value to the conversation atleast don't try to demean it. – sublime Apr 18 '14 at 03:47
  • @sublime - geez. I asked a simple question about why because that is something I like to understand before I contribute and I feel like I am being attacked for wanting to understand why. I'm perfectly fine if others want to pursue this. Bye. – jfriend00 Apr 18 '14 at 03:50
  • @ErikReppen I now see your point, read the question again it's "why would this code not cause an infinite loop?" – HMR Apr 18 '14 at 04:54

2 Answers2

5

Using more common style:

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

In ECMA-262, the internal prototype property is denoted by [[Prototype]].

Assigning a different object to P.prototype does not modify P's [[Prototype]], so its inheritance chain remains as:

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

Given that P and P.prototype both point to the same object, the [[prototype]] chain of an instance of P is:

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

so no endless loop.

Without the assignment to P.prototype, p's prototype chain would have been:

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

To get an endless loop, you can assign an object to its own __proto__ property (the public way to access [[Prototype]]) in those browsers that support it, but I'm not sure that's a good idea, Firefox throws:

"TypeError: cyclic __proto__ value".
RobG
  • 142,382
  • 31
  • 172
  • 209
  • so how do I get it in endless loop? – sublime Apr 18 '14 at 00:04
  • see this, hopefully it will help: http://stackoverflow.com/questions/12970308/javascript-inheritance-infinite-loop and/or this: http://stackoverflow.com/questions/13720659/javascript-inheritance-infinite-loop-when-using-superclass-function – james emanon Apr 18 '14 at 00:16
  • @OneKitten : I tried that too :) I thought it was a chrome thing, so I did the same thing but in node.js and got the same error. Later realized that node.js is v8 as well :) – sublime Apr 18 '14 at 00:42
1

Well, to your first question:

var p = function(){};

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

var q = new p();

In the first one, all you're doing when you create an instance of p is setting the prototype to the function p itself, which is an object in its own right (with properties such as length, prototype, etc.). Its actual internal prototype is Function.prototype, which in turn has a prototype of Object.prototype.

The second one is slightly different -- close, but no cigar. When you're assigning new p() to p.prototype, the prototype property has not been set yet, so you're just going to get the original value of the prototype property as the instance's internal prototype.


Moving on to your second question. I don't actually see why you'd do this, as every property would be shadowed by its own instance property.

Even if you were allowed to (no browsers do), there would be no point.

Consider this:

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

Let's assume that this works, ignore the fact that this throws a TypeError in all browsers (which is specified for browsers in Annex B of the upcoming ES6 spec).

If you were to access the property b, you'd never go up the prototype chain.

If you attempted to access a non-existent property, an implementation (if it allowed for such a thing) could either go up the prototype chain, back to itself recursively, or recognise that the property would never be found and return undefined.

Of course, there is the situation where there are multiple objects involved:

var a = { x: 1 };
var b = { y: 2 };
b.__proto__ = a;
a.__proto__ = b;

However, this is ridiculously stupid and of no practical use (if permitted in the first place -- it isn't).

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83