如何__ proto__ 不同于构造函数。原型?

function Gadget(name, color)
{
this.name = name;
this.color = color;
}


Gadget.prototype.rating = 3


var newtoy = new Gadget("webcam", "black")


newtoy.constructor.prototype.constructor.prototype.constructor.prototype

它总是返回等级 = 3的对象。

但如果我这么做:

newtoy.__proto__.__proto__.__proto__

链最终返回 null

同样在 Internet Explorer 中,如果没有 __proto__属性,我该如何检查 null?

56205 次浏览

constructor是函数对象的 prototype属性所指向的对象的预定义的[[ DontEnum ]]属性,它最初指向函数对象本身。

__proto__相当于一个对象的内部[[ Prototype ]]属性,即它的实际原型。

使用 new操作符创建对象时,其内部的[[ Prototype ]]属性将被设置为构造函数的 prototype属性所指向的对象。

这意味着 .constructor将求值为 .__proto__.constructor,即用于创建对象的构造函数,正如我们所了解的,这个函数的 protoype属性用于设置对象的[[ Prototype ]]。

因此,.constructor.prototype.constructor.constructor完全相同(只要这些属性没有被覆盖) ; 请参阅 给你以获得更详细的解释。

如果 __proto__可用,您可以遍历对象的实际原型链。在普通的 ECMAScript3中无法做到这一点,因为 JavaScript 不是为深层继承层次结构设计的。

最近我一直在试图理解这个问题,最后终于想出了这个“地图”,我认为这个“地图”可以充分揭示这个问题

Http://i.stack.imgur.com/kfzi3.png enter image description here

我知道我不是第一个编造这个故事的人,但是找到它更有趣。不管怎样,在那之后,我发现了另一个图表,我认为它说的基本上是一样的:

Javascript 对象布局

最让我吃惊的是,我发现 Object.__proto__指向 Function.prototype,而不是 Object.prototype,但我相信这是有原因的: -)

如果有人想要测试它,我也会在这里粘贴图片中提到的代码。注意,一些属性被添加到对象中,以便在一些跳转之后更容易知道我们在哪里:

Object.O1='';
Object.prototype.Op1='';


Function.F1 = '';
Function.prototype.Fp1 = '';


Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';


mycat = new Cat();
o = {};


// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);

Object是夏娃,Function是亚当,亚当(Function)用他的骨头(Function.prototype)创造夏娃(Object)。那么是谁创造了亚当(Function) ?JavaScript 语言的发明者:。

根据 utsaina 的回答,我想添加更多有用的信息。

最让我惊讶的是发现 Object.__proto__ 指向 Function.prototype,而不是 Object.prototype,但是我 肯定有一个很好的理由: -)

不应该是这样的。Object.__proto__不应该指向 Object.prototype。相反,Objectoo.__proto__的实例应该指向 Object.prototype

(请原谅我在 JavaScript 中使用术语 classinstance,但您知道: -)

我认为类 Object本身就是 Function的一个实例,这就是为什么 Object.__proto__ === Function.prototype。因此: Object是夏娃,Function是亚当,亚当(Function)用他的骨头(Function.prototype)创造夏娃(Object)。

此外,甚至类 Function本身也是 Function本身的一个实例,即 Function.__proto__ === Function.prototype,这也是为什么 Function === Function.constructor

此外,正则类 CatFunction的一个实例,即 Cat.__proto__ === Function.prototype

上述原因是,当我们用 JavaScript 创建一个类时,实际上,我们只是在创建一个函数,它应该是 Function的一个实例。ObjectFunction只是特殊的,但他们仍然是类,而 Cat是一个常规类。

作为一个因素,在 GoogleChromeJavaScript 引擎中,以下4个:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • Cat.__proto__

它们都是 ===(绝对相等) ,它们的值是 function Empty() {}

> Function.prototype
function Empty() {}
> Function.__proto__
function Empty() {}
> Object.__proto__
function Empty() {}
> Cat.__proto__
function Empty() {}
> Function.prototype === Function.__proto__
true
> Function.__proto__ === Object.__proto__
true
> Object.__proto__ === Cat.__proto__
true

好的。那么是谁创建了特殊的 function Empty() {}(Function.prototype) ? 想想看: -)

JavaScript 中的 Prototype 继承基于 __proto__属性,从某种意义上说,每个对象都继承由其 __proto__属性引用的对象的内容。

prototype属性仅对于 Function对象是特殊的,并且只有在使用 new操作符作为构造函数调用 Function时才是特殊的。在这种情况下,创建的对象的 __proto__将被设置为构造函数的 Function.prototype

这意味着添加到 Function.prototype将自动反映 __proto__引用 Function.prototype的所有对象。

用另一个对象替换构造函数的 Function.prototype将使 没有更新任何已存在对象的 __proto__属性。

请注意,不应直接访问 __proto__属性,而应使用 GetPrototypeOf (object)

为了回答第一个问题,我已经创建了一个 __proto__prototype引用的定制图表,不幸的是,stackoverflow 不允许我添加“声誉小于10”的图像。改天吧。

[编辑] 该图使用 [[Prototype]]而不是 __proto__,因为 ECMAScript 规范就是这样引用内部对象的。我希望你能解决所有问题。

这里有一些提示可以帮助你理解这个数字:

red    = JavaScript Function constructor and its prototype
violet = JavaScript Object constructor and its prototype
green  = user-created objects
(first created using Object constructor or object literal {},
second using user-defined constructor function)
blue   = user-defined function and its prototype
(when you create a function, two objects are created in memory:
the function and its prototype)

请注意,constructor属性不存在于创建的对象中,而是从原型继承的。

enter image description here

每个函数都创建了它的原型。 当我们使用函数构造函数创建一个对象时,我的对象的 原型属性将开始指向该函数的原型。

我真的不知道为什么人们没有纠正你在哪里的实际问题在你的理解。

这会让你更容易发现问题

让我们看看发生了什么:

var newtoy = new Gadget("webcam", "black")


newtoy
.constructor //newtoy's constructor function is newtoy ( the function itself)
.prototype // the function has a prototype property.( all functions has)
.constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ? )  ! it is not(!) the constructor function  !!! this is where your mess begins. it points back to the constructor function itself ( newtoy function)
.prototype // so again we are at line 3 of this code snippet
.constructor //same as line 4 ...
.prototype
rating = 3

很好,现在让我们看看这个 __proto__

在此之前,请记住关于 __proto__的两件事:

  1. 当您使用 new操作符创建一个对象时,它的内部 [[Prototype]]/proto__属性将被设置为它的 constructor functionprototype属性(1) ,或者如果您愿意,可以设置为“创建者”。

  2. 硬编码在 JS ー: Object.prototype.__proto__null

我们把这两点称为“ bill

newtoy
.__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`.
.__proto__ // Ok so now our starting point is `Gadget.prototype`. so  regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`.  Ok .( continuing "bill" ) does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of   its `constructor function`"
.__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype ( as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED

好点了吗?

如果所有这些数字都是压倒性的,让我们看看这些属性意味着什么。

STH.prototype

当创建一个新函数时,有一个空对象被并行创建,并用 [[Prototype]]链链接到该函数。要访问这个对象,我们使用函数的 prototype属性。

function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}

请记住,prototype属性只对函数可用。

构造函数

上面提到的原型对象除了 one-constructor之外没有其他属性。此属性表示创建原型对象的函数。

var toy = new Gadget();

在创建 Gadget函数时,我们也创建了一个类似于 {constructor: Gadget}的对象——这与 Gadget.prototype完全不同。由于 constructor指的是创建对象原型的函数,因此 toy.constructor代表 Gadget函数。我们写 toy.constructor.prototype,我们又得到了 {constructor: Gadget}

因此,这里有一个恶性循环: 你可以使用 toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype,它总是 Gadget.prototype

toy
.constructor    // Gadget
.prototype    // {constructor: Gadget}
.constructor    // Gadget
.prototype    // {constructor: Gadget}
// ...

原型

虽然 prototype是特定于函数的属性,但是 __proto__可用于 Object.prototype中的所有对象。它指的是能够创建对象的函数的原型。

[].__proto__ === Array.prototype
// true


({}).__proto === Object.prototype
// true

这里,toy.__proto__Gadget.prototype。由于 Gadget.prototype是一个对象({}) ,而对象是用 Object函数创建的(参见上面的例子) ,所以我们得到了 Object.prototype。这是 JavaScript 中的高级对象,它的 __proto__只能指示 null

toy
.__proto__    // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__    // Object.prototype (topmost object in JS)
.__proto__    // null - Object.prototype is the end of any chain

简短的回答: __proto__是对创建对象的构造函数的 prototype属性的引用。

JavaScript 中的对象

JavaScript 对象是具有零个或多个属性的 收藏品的内置类型。属性是容纳其他对象、基元值或函数的容器。

JavaScript 中的构造函数

函数是常规对象(在 ECMA-262术语中实现 [[Call]]) ,具有可调用的额外功能,但在 JavaScript 中扮演另一个角色: 如果通过 new操作符调用,它们将成为构造函数(对象的 工厂)。因此,构造函数与其他语言中的类大致相似。

每个 JavaScript 函数实际上都是 Function内置函数对象的一个实例,它具有一个名为 prototype的特殊属性,用于实现基于原型的继承和共享属性。由构造函数创建的每个对象都有一个 含蓄引用(称为原型或 __proto__) ,该引用指向其构造函数 prototype的值。

构造函数 prototype是一种用于构建对象的 蓝图,因为构造函数创建的每个对象都继承对其 prototype的引用。

原型链

对象通过内部属性 [[Prototype]]__proto__指定其原型。两个对象之间的原型关系是关于继承的: 每个对象都可以有另一个对象作为其原型。原型可能是 null值。

__proto__属性连接的对象链称为 原型链。当对对象中的属性进行引用时,该引用指的是原型链中包含该名称的属性的第一个对象中遇到的属性。原型链的行为就好像它是一个单独的对象。

prototype-inheritance.jpg

每当您尝试访问一个对象中的属性时,JavaScript 就会开始在该对象中搜索该属性,并继续使用其原型、原型的原型等等,直到遇到该属性或者如果 __proto__持有值 null

这种使用原型链的继承类型通常称为 代表团,以避免与使用类链的其他语言混淆。

几乎所有对象都是 Object的实例,因为 Object.prototype是原型链中的最后一个。但是 Object.prototype不是 Object的实例,因为 Object.prototype.__proto__保存值 null

您还可以使用 null原型创建一个对象,如下所示:

var dict = Object.create(null);

这样的一个对象是一个比文字对象更好的映射(dictionary) ,这就是为什么这种模式有时被称为 迪克特模式(对于 dictionary 来说是 迪克特)。

注意: 使用 {}创建的文本对象是 Object的实例,因为 ({}).__proto__是对 Object.prototype的引用。