我正在学习Javascript中的原型继承,并且据我所知,我正在尝试使用它将进程发送到无限递归链接。
我对原型继承的想法是一个对象(它是一个函数)保存原型链接。该对象的任何实例都指向它。因此,如果我说instance.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.
我想知道为什么这不起作用,我怎么能让它进入无限循环。
答案 0 :(得分:5)
使用更常见的风格:
function P(){};
P.prototype = P;
在ECMA-262中,internal prototype property由[[Prototype]]
表示。
为 P.prototype 分配不同的对象不会修改 P 的[[Prototype]]
,因此其继承链保持为:
P : P[[Prototype]] -> Function.prototype -> Object.prototype -> null
鉴于 P 和 P.prototype 都指向同一个对象, P 实例的[[prototype]]
链是:
p : p[[Prototype]] -> P : P[[Prototype]] -> Function.prototype -> Object.prototype -> null
所以没有无限循环。
如果没有分配给 P.prototype ,那么 p 的原型链就是:
p : p[[Prototype]] -> P.prototype -> Object.prototype -> null
要获得无限循环,您可以在支持它的浏览器中将对象分配给自己的__proto__
属性(访问[[Prototype]]
的公共方式),但我不确定是好主意,Firefox抛出:
"TypeError: cyclic __proto__ value".
答案 1 :(得分:1)
那么,对你的第一个问题:
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
属性尚未设置,因此您只需获取{{1}的原始值} property作为实例的内部原型。
继续你的第二个问题。我实际上并不明白为什么要这样做,因为每个属性都会被自己的实例属性所遮蔽。
即使你被允许(没有浏览器这样做),也没有意义。
考虑一下:
prototype
让我们假设这是有效的,忽略了这会在所有浏览器中引发TypeError的事实(为即将推出的ES6规范的附录B中的浏览器指定)。
如果您要访问该属性var a = { b: 1 };
a.__proto__ = a;
,那么您永远不会进入原型链。
如果你试图访问一个不存在的属性,一个实现(如果它允许这样的事情)可以上升到原型链,递归回到自身,或者认识到永远不会找到该属性并返回undefined
当然,存在涉及多个对象的情况:
b
然而,这是非常愚蠢的,没有实际用途(如果首先允许的话 - 它不是)。