这不是那么简单。 __proto__
属性是到.constructor
的原型的动态链接。
但是,.constructor
在这些情况下不会被覆盖(虽然它可以在某些手工库中)。
当你正在寻找一个参考Foo
以显示在该链中时,这是一个非常“古典”的观点,而不是原型继承,它从具体实例继承而不是类,以及在JS的情况下,引用(当不是标量),而不是副本。
对TL;博士原因很简单:Object.create
的构造是Object
,{}
的构造是Object
和Object.prototype
的构造是Object
。
很长的路要走
首先要知道:在这些查找
名称是不依赖于变量,而是他们绑功能,通常。
曾几何时,在那里可以找到这些信息被隐藏,而现在它的发现它的方式在许多浏览器功能(function Foo() { } Foo.name; //Foo
)的.name
属性现在(很像曾经是无形__proto__
领域。
第二位:
您在控制台参考和类型检查中看到的名称不是基于原型,而是基于名为.constructor
的属性。
// Equivalent assignments
var obj1 = { };
var obj2 = new Object();
var obj3 = Object.create(Object.prototype);
obj1.constructor; // Object
obj2.constructor; // Object
obj3.constructor; // Object
如果我们要改变的动态一点,并引入更多的“经典”的方法,以实例的创建,这是paseé,但会看到死灰复燃ES6与class
糖...
function Foo() {
this.isFoo = true;
}
var foo = new Foo();
foo.isFoo; // true
foo.constructor; // Foo
foo.__proto__ === Foo.prototype; // true
foo.__proto__.constructor; // Object
最后一点点是说,为你的直接问题; Foo.prototype
不过是一个简单的例子。
在JS的日子里,每个人都在寻找让JS感觉像Java/C#的最好的方式,你会看到类似:
function Foo() { }
function Bar() { }
Bar.prototype = new Foo();
var foo = new Foo();
var bar = new Bar();
bar instanceof Bar; // true
bar instanceof Foo; // true
一方面,这类作品,因为我们已经能够在Bar的实例上重用Foo的方法。
Grand。
立即的缺点是Bar
的所有实例共享Foo
的相同实例,包括其所有实例特定的属性。
尽管这种方法与我所建议的重用模式相去甚远,但它的确展示了您的困境。
// using the last set of assignments
bar instanceof Foo;
// equivalent to:
bar.constructor === Foo; // false
bar.__proto__.constructor === Foo; // true
// not equivalent to
bar.__proto__ == Foo;
更现代的“经典”继承(调用super
构造,抄袭其他构造函数的原型到您的新构造等)的形式做,让您撰写和再利用方法的工作做得更好......
但是,这是以能够依靠__proto__
链来查找那些借出的方法来自何处为代价的。
在历史上,“坏了再利用,有利于类型检查”模式让您搜索
val.__proto__.__proto__.__proto__.__proto__. (...) .__proto__.constructor
,直到它符合您instanceof
,或者直到你在该行的末尾打Object
。
新形式的值复制到直接val.__proto__
(/ val.constructor.prototype
,这是我们所看到的是同一个对象,在创建val
),这意味着你的原型链很快耗尽。
“__proto__”显示为“Object” - 但“Foo”和“Bar”也一样。你期望它显示为什么?有很好的理由不把它显示为'Foo' - 对象不知道什么名字指向它们。 – user2357112
@ user2357112为什么你不期望它包含对它链接到的对象的引用? – shmuli