0

我正在读凯尔辛普森的“YDKJS:这个&对象原型”,并看他的行为代表团的例子。这里的代码如下:为什么__proto__对象在调试器中评估为“Object”?

Foo = { 
    init: function(who) { 
     this.me = who; 
    }, 
    identify: function() { 
     return "I am " + this.me; 
    } 
}; 

Bar = Object.create(Foo); 

Bar.speak = function() { 
    alert("Hello, " + this.identify() + "."); 
}; 

var b1 = Object.create(Bar); 
b1.init("b1"); 
var b2 = Object.create(Bar); 
b2.init("b2"); 

b1.speak(); 
b2.speak(); 

他用这个图来描述这些对象之间的关系:

现在我的问题:

当这个代码在Chrome开发人员工具修修补补,我看到__proto__对象的评估结果为Object。这是为什么? __proto__对象不应该描绘图中的实际关系,其中b1b2委托给Bar,然后委托给Foo?为什么这些关系没有在__proto__对象中明确命名?总而言之,该实现使用Object.create()方法,并在proto参数(第一个参数)中放置参数。难道不希望控制台会将该命名参数作为__proto__对象的值返回吗?

enter image description here

+0

“__proto__”显示为“Object” - 但“Foo”和“Bar”也一样。你期望它显示为什么?有很好的理由不把它显示为'Foo' - 对象不知道什么名字指向它们。 – user2357112

+0

@ user2357112为什么你不期望它包含对它链接到的对象的引用? – shmuli

回答

2

这不是那么简单。 __proto__属性.constructor的原型的动态链接。

但是,.constructor在这些情况下不会被覆盖(虽然它可以在某些手工库中)。

当你正在寻找一个参考Foo以显示在该链中时,这是一个非常“古典”的观点,而不是原型继承,它从具体实例继承而不是类,以及在JS的情况下,引用(当不是标量),而不是副本。

对TL;博士原因很简单:Object.create的构造是Object{}的构造是ObjectObject.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),这意味着你的原型链很快耗尽。

+0

感谢您花时间写出清晰彻底的回复!我觉得我欠你一些东西。大声笑! – shmuli

相关问题