为什么__proto__对象评估为"对象"在调试器中?

时间:2015-04-27 00:31:54

标签: javascript debugging prototype google-chrome-devtools prototypal-inheritance

我正在读Kyle Simpson" YDKJS:这个&对象原型",并查看他的行为委托示例。这是以下代码:

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委托给BarFoo转而委托给__proto__ ?为什么这些关系没有在Object.create()对象中明确命名?总而言之,此实现使用proto方法,并在__proto__参数(第一个参数)中放置一个参数。是不是期望控制台将该命名参数作为CALIBRATED对象的值返回?

enter image description here

1 个答案:

答案 0 :(得分:2)

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

但是,.constructor在这些情况下不会被覆盖(尽管它可以在某些手工制作的库中)。

当您正在寻找对Foo显示在该链中的引用时,它是一个非常“经典”的观点,与原型继承关系不大,原型继承是从具体实例继承的,而不是类,在JS的情况下,引用(当不是标量时),而不是副本。

tl; dr原因很简单:Object.create的构造函数是Object{}的构造函数是Object,而Object.prototype的构造函数是Object

长路

首先要知道的是:
这些查找中的名称与变量无关,而是通常与函数相关联 曾几何时,可以找到可以找到此信息的字段,现在发现它现在可以在许多浏览器中找到函数.name的属性(function Foo () { } Foo.name; //Foo)(很像{{1以前是不可见的。

第二位:
您在控制台引用和类型检查中看到的名称不是基于 proto ,而是基于名为__proto__的属性。

.constructor

如果我们要稍微改变一下动态,并为实例创建引入更“经典”的方法,那就是paseé,但会看到ES6中的// Equivalent assignments var obj1 = { }; var obj2 = new Object(); var obj3 = Object.create(Object.prototype); obj1.constructor; // Object obj2.constructor; // Object obj3.constructor; // Object 糖复活......

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#的最佳方式,你会看到类似的东西:

Object

一方面,这种作品,因为我们已经能够在Bar的实例上重用Foo的方法。
大。
直接的缺点是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

更多现代形式的“经典”继承(调用 // 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时看到的是同一个对象,这意味着你的原型链用完了很快。