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?
9条答案
按热度按时间mf98qq941#
我最近一直在努力思考这个问题,最后终于想出了这个“Map”,我认为它能充分揭示这一问题
http://i.stack.imgur.com/KFzI3.png
我知道我不是第一个做这个,但它是更有趣的弄清楚,找到它:-).无论如何,在那之后,我发现,例如,这另一个图表,我认为说基本相同:
Javascript object layout
最让我惊讶的是发现
Object.__proto__
指向Function.prototype
,而不是Object.prototype
,但我相信这是有原因的:-)如果有人想测试的话,我也把图片中提到的代码粘贴到这里。注意,一些属性被添加到对象中,以便在一些跳转后容易知道我们在哪里:
mu0hgdu02#
constructor
是由函数对象的prototype
属性指向的对象的预定义DontEnum属性,并且将最初指向函数对象本身。__proto__
等价于一个对象的内部Prototype属性,即它的实际原型。当你用
new
操作符创建一个对象时,它的内部Prototype属性将被设置为构造函数的prototype
属性所指向的对象。这意味着
.constructor
将计算为.__proto__.constructor
,即用于创建对象的构造函数,正如我们所知,该函数的protoype
属性用于设置对象的Prototype。.constructor.prototype.constructor
与.constructor
相同(只要这些属性没有被覆盖);参见X1 E0 F1 X以获得更详细的解释。如果
__proto__
可用,您可以遍历对象的实际原型链,但在普通ECMAScript 3中无法实现这一点,因为JavaScript不是为深度继承层次结构设计的。guykilcj3#
JavaScript中的Prototypal Inheritance基于
__proto__
属性,从某种意义上说,每个对象都继承其__proto__
属性所引用的对象的内容。prototype
属性仅对Function
对象特殊,并且仅在使用new
运算符调用Function
作为构造函数时特殊。在这种情况下,所创建对象的__proto__
将设置为构造函数的Function.prototype
。这意味着添加到
Function.prototype
将自动反映在其__proto__
引用Function.prototype
的所有对象上。用另一个对象替换构造函数的
Function.prototype
将不会更新任何现有对象的__proto__
属性。请注意,不应直接访问
__proto__
属性,而应使用Object.getPrototypeOf(object)。为了回答第一个问题,我创建了一个
__proto__
和prototype
引用的定制图,不幸的是stackoverflow不允许我添加“少于10个声望”的图片。[编辑]图中使用了
[[Prototype]]
而不是__proto__
,因为ECMAScript规范是这样引用内部对象的,希望你能把一切都弄清楚。以下是一些帮助您理解该图的提示:
请注意,
constructor
属性不存在于创建的对象中,而是从原型继承的。kcwpcxri4#
Object
是夏娃,Function
是亚当,亚当(Function
)用他的骨头(Function.prototype
)创造了夏娃(Object
)。那么是谁创造了亚当(Function
)?--JavaScript语言的发明者:-)。根据utsaina的回答,我想添加更多有用的信息。
最让我惊讶的是发现
Object.__proto__
指向Function.prototype
,而不是Object.prototype
,但我相信这是有原因的:-)它不应该是。
Object.__proto__
不应该指向Object.prototype
。相反,Object
o
、o.__proto__
的示例应该指向Object.prototype
。(请原谅我在JavaScript中使用术语
class
和instance
,但你知道它:-)我认为类
Object
本身就是Function
的一个示例,这就是为什么Object.__proto__ === Function.prototype
。Object
是夏娃,Function
是亚当,亚当(Function
)用他的骨头(Function.prototype
)创造了夏娃(Object
)。此外,即使类
Function
本身也是Function
本身的示例,即Function.__proto__ === Function.prototype
,这也是为什么Function === Function.constructor
此外,正规类
Cat
是Function
的示例,即Cat.__proto__ === Function.prototype
。之所以会出现上述情况,是因为我们在JavaScript中创建类时,实际上只是在创建一个函数,这个函数应该是
Function
的一个示例,Object
和Function
只是特殊的,但它们仍然是类,而Cat
是一个常规类。作为一个因素,在Google Chrome JavaScript引擎中,以下4项:
Function.prototype
Function.__proto__
Object.__proto__
它们都是
===
(绝对等于),它们的值是function Empty() {}
好的。那么是谁创建了特殊的
function Empty() {}
(Function.prototype
)呢?想一想:-)y53ybaqx5#
我真的不知道为什么人们没有纠正你关于哪里的实际问题在你的理解。
这将使您更容易发现问题
我们来看看到底发生了什么:
很好,现在我们来看一下
__proto__
在此之前,请记住关于
__proto__
的两件事:1.当您使用
new
运算符创建对象时,其内部[[Prototype]]
/proto__
属性将设置为其constructor function
的prototype
属性(1)或“创建者”(如果您愿意)。1.在JS -内硬编码:是一个。
我们将这两个点称为“
bill
“好点了?
5t7ly7z56#
每个函数都会创建它的原型,当我们用函数构造函数创建一个对象时,对象的**proto**属性会指向函数的原型。
c6ubokkw7#
如果所有这些数字都是压倒性的,让我们来看看这些属性意味着什么。
∮ ∮ ∮ ∮ ∮一个月一个月
在创建新函数时,有一个空对象被并行创建,并通过
[[Prototype]]
链链接到该函数。要访问该对象,我们使用该函数的prototype
属性。prototype
属性仅适用于函数。*STH.构造函数
上面提到的prototype对象除了一个属性-
constructor
之外没有其他属性。这个属性代表了一个创建prototype对象的函数。在创建
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
。STH.原型
prototype
是函数特有的属性,而__proto__
在Object.prototype
中是所有对象都可用的,它指的是可以创建对象的函数的原型。这里
toy.__proto__
就是Gadget.prototype
,由于Gadget.prototype
是一个对象({}
),对象是用Object
函数创建的(见上例),我们得到Object.prototype
,这是JavaScript中的高级对象,它的__proto__
只能表示null
。nnt7mjpx8#
简短回答:
__proto__
是对创建对象的构造函数的prototype
属性的引用。JavaScript中的对象
JavaScript对象是零个或多个属性的 * 集合 * 的内置类型。属性是保存其他对象、原始值或函数的容器。
JavaScript中的构造函数
函数是常规对象(按照ECMA-262的术语实现
[[Call]]
),具有可调用的附加功能,但在JavaScript中扮演另一个角色:如果通过new
操作符调用,它们就成为构造函数(对象的 * 工厂 *)。构造函数因此大致类似于其他语言中的类。每个JavaScript函数实际上都是
Function
内置函数对象的一个示例,该函数对象有一个名为prototype
的特殊属性,用于实现基于原型的继承和共享属性。每个由构造函数创建的对象都有一个对其构造函数prototype
的值的 * 隐式 * 引用(称为原型或__proto__
)。构造函数
prototype
是构建对象的一种“蓝图”,因为构造函数创建的每个对象都继承了对其prototype
的引用。原型链
对象通过内部属性
[[Prototype]]
或__proto__
指定其原型,两个对象之间的原型关系是继承:每个对象可以有另一个对象作为其原型。原型可以是null
值。由
__proto__
属性连接的对象链称为 prototype chain。当引用对象中的属性时,该引用是指在原型链中包含该名称属性的第一个对象中遇到的属性。原型链的行为就像是单个对象。每当您尝试访问对象中的属性时,JavaScript都会在该对象中开始搜索该属性,并继续搜索其原型、原型的原型等,直到遇到该属性或
__proto__
的值为null
。这种使用原型链的继承通常称为 delegation,以避免与使用类链的其他语言混淆。
几乎所有的对象都是
Object
的示例,因为Object.prototype
在它们的原型链中是最后一个,但是Object.prototype
不是Object
的示例,因为Object.prototype.__proto__
拥有值null
。您还可以使用
null
原型创建对象,如下所示:这样的对象是比文本对象更好的Map(字典),这就是为什么这种模式有时被称为 dict 模式(dict 表示字典)。
注意:使用
{}
创建的文本对象是Object
的示例,因为({}).__proto__
是对Object.prototype
的引用。mf98qq949#
JavaScript中的原型让每个人都感到困惑
下面是一个更简单的解释。下面是JavaScript中的大多数对象是如何继承的,从null开始一直到对象类型:
这里是证明!下面我只是要求为每个对象找到原型。注意:
Object.prototype.toString.call()
只告诉我们原型的字符串名称:请注意,字符串“[object Function]”表示类型的“prototype”或父对象是“Function.prototype”。因此,它是在每个级别分配的底层原型父对象的表示。现在让我们更深入地解释一下...
JavaScript中的***prototype***一词的含义如下:
原型中的怪异
所以,在JavaScript继承中,所有的东西都是从函数类型开始的!为什么呢?这是因为你不能创建任何对象“类型”(对象,数组,函数,字符串等)没有函数。当你这样做的时候,它们仍然是从函数中某处调用的“构造函数”构造的。函数及其构造函数不仅是从类型创建新对象,而且还分配“prototype”属性、“proto”属性以及继承的 * prototype * 或子对象将使用的对象的实际树。
JavaScript中的对象有两种状态,“类型”和实际示例化的对象。这就是为什么“对象”与“const x = {}"创建的对象不一样。这就是为什么“类型”开始时与它的最终继承或原型不同。
看看这个!
后来呢?
结果是FUNCTION CONSTRUCTOR在创建对象时创建并分配最终的
prototype
。但是在创建数组对象之前和之后,都可以使用更多的属性、对象等修改自定义原型。因此,最终分配的原型由Function对象的构造函数设置,如上所示,该对象是Array类型的初始原型。所以要知道,
Function.prototype
是JavaScript中所有对象类型的主要原型!它位于所有对象之下,而是创建最终示例化对象的工具,该对象在创建时被分配了自己的原型。注意,“Array.prototype”具有其父原型Object.prototype
,其具有父原型“null”。因此Object.prototype
仍然是所有这些对象继承的顶级父对象,但是在创建它们的过程中,构造函数会在新对象创建时更改所有子对象的直接父对象。注意,
Function.prototype
从它自己的对象原型中获得了许多特性。它也继承了原型。它为您创建的对象构建的原型也是从这个父原型中创建的。因此,最后,Object.prototype
提供了函数类型和所有类型创建所需的好东西,并管理分配给它们的原型。请记住,函数就像对象一样,是一个特殊的预处理器。内置类型的特殊工具和功能需要创建所有类型的对象!最后一个测试....让我们看看prototype是如何为我们创建的自定义对象工作的。下面的例子证明了函数构造函数(Function.prototype 的一部分)将**“prototype”**属性分配给创建的对象,但可以在 * 分配给
MyCustomObject.prototype
的对象原型 * 之前 * 或 * 之后 * 使用各种属性和方法进行自定义。这表明对象的最终原型不必是Object.prototype
继承属性的静态副本,而可以是您创建的全新对象!