javascript __proto__与构造函数.prototype有何不同?

fd3cxomn  于 2022-12-17  发布在  Java
关注(0)|答案(9)|浏览(123)
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?

mf98qq94

mf98qq941#

我最近一直在努力思考这个问题,最后终于想出了这个“Map”,我认为它能充分揭示这一问题
http://i.stack.imgur.com/KFzI3.png

我知道我不是第一个做这个,但它是更有趣的弄清楚,找到它:-).无论如何,在那之后,我发现,例如,这另一个图表,我认为说基本相同:
Javascript object layout
最让我惊讶的是发现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);
mu0hgdu0

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不是为深度继承层次结构设计的。

guykilcj

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规范是这样引用内部对象的,希望你能把一切都弄清楚。
以下是一些帮助您理解该图的提示:

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属性不存在于创建的对象中,而是从原型继承的。

kcwpcxri

kcwpcxri4#

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.prototypeObject是夏娃,Function是亚当,亚当(Function)用他的骨头(Function.prototype)创造了夏娃(Object)。
此外,即使类Function本身也是Function本身的示例,即Function.__proto__ === Function.prototype,这也是为什么Function === Function.constructor
此外,正规类CatFunction的示例,即Cat.__proto__ === Function.prototype
之所以会出现上述情况,是因为我们在JavaScript中创建类时,实际上只是在创建一个函数,这个函数应该是Function的一个示例,ObjectFunction只是特殊的,但它们仍然是类,而Cat是一个常规类。

作为一个因素,在Google Chrome JavaScript引擎中,以下4项:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • x1米39英寸

它们都是===(绝对等于),它们的值是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)呢?想一想:-)

y53ybaqx

y53ybaqx5#

我真的不知道为什么人们没有纠正你关于哪里的实际问题在你的理解。
这将使您更容易发现问题
我们来看看到底发生了什么:

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)或“创建者”(如果您愿意)。
1.在JS -内硬编码:是一个。
我们将这两个点称为“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

好点了?

5t7ly7z5

5t7ly7z56#

每个函数都会创建它的原型,当我们用函数构造函数创建一个对象时,对象的**proto**属性会指向函数的原型。

c6ubokkw

c6ubokkw7#

如果所有这些数字都是压倒性的,让我们来看看这些属性意味着什么。
∮ ∮ ∮ ∮ ∮一个月一个月
在创建新函数时,有一个空对象被并行创建,并通过[[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属性仅适用于函数。*

STH.构造函数

上面提到的prototype对象除了一个属性-constructor之外没有其他属性。这个属性代表了一个创建prototype对象的函数。

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}
// ...

STH.原型

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
nnt7mjpx

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原型创建对象,如下所示:

var dict = Object.create(null);

这样的对象是比文本对象更好的Map(字典),这就是为什么这种模式有时被称为 dict 模式(dict 表示字典)。
注意:使用{}创建的文本对象是Object的示例,因为({}).__proto__是对Object.prototype的引用。

mf98qq94

mf98qq949#

JavaScript中的原型让每个人都感到困惑

下面是一个更简单的解释。下面是JavaScript中的大多数对象是如何继承的,从null开始一直到对象类型:

String   < Function < Object < null
Array    < Function < Object < null
Object   < Function < Object < null
Function < Function < Object < null

这里是证明!下面我只是要求为每个对象找到原型。注意:Object.prototype.toString.call()只告诉我们原型的字符串名称:

Object.prototype.toString.call(String);// [object Function]
Object.prototype.toString.call(Array);// [object Function]
Object.prototype.toString.call(Object);// [object Function]
Object.prototype.toString.call(Function);// [object Function]

Object.prototype.toString.call(String.__proto__);// [object Function]
Object.prototype.toString.call(Array.__proto__);// [object Function]
Object.prototype.toString.call(Object.__proto__);// [object Function]
Object.prototype.toString.call(Function.__proto__);// [object Function]

Object.prototype.toString.call(String.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Array.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Object.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Function.__proto__.__proto__);// [object Object]

Object.prototype.toString.call(String.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Array.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Object.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Function.__proto__.__proto__.__proto__);// [object Null]

请注意,字符串“[object Function]”表示类型的“prototype”或父对象是“Function.prototype”。因此,它是在每个级别分配的底层原型父对象的表示。现在让我们更深入地解释一下...
JavaScript中的***prototype***一词的含义如下:

  • JavaScript中的所有对象最终都继承自一系列原型或“基类”,这些原型或“基类”通过继承分配它们的各种属性和功能。这沿着树向下级联到底部的子对象。在JavaScript中,所有对象最终都继承自 Object.prototype,它靠近继承树的顶部。
  • 术语“原型”是指具有由子对象继承的属性和方法的特殊对象
  • “prototype”也是JavaScript中所有对象的一个特殊属性,它将一个给定对象作为父原型分配给一个子对象,但也赠款更改原型的权限。它控制分配给一个子对象的实际原型,但也像一个真正的类属性一样,您可以使用它来操作一个子对象的原型。我不建议您这样做,但是你可以修改所有对象继承的原始对象原型,方法是使用简单的属性添加来添加新属性,或者通过包含属性的 Object Literal 来添加属性:
Object.prototype.myproperty = "Hello World";
    Object.prototype.myobjectproperties = {text1: "Hello", text2: "World"};
  • “prototype”属性与子对象名称一起表示为“MyObjectType.prototype”。这个新名称现在既是父原型的标识符,也是更改父原型的工具。但它不是对实际原型对象的引用!(这在下面使用__proto__完成)。当创建该类型的所有新对象时,它被分配给所有新对象。它首先被赋值给生成对象的函数构造函数,然后传递给函数构造函数创建的对象。
  • proto”是对分配给子对象的实际原型对象的引用。它也是一个属性,但它是一个引用。因此它用于沿子对象继承的原型对象树向上移动,并访问它们及其属性。下面的示例从创建的对象文字沿树向上移动,并在顶部以“null”结束:
alert({}.__proto__.__proto__);// null

原型中的怪异

所以,在JavaScript继承中,所有的东西都是从函数类型开始的!为什么呢?这是因为你不能创建任何对象“类型”(对象,数组,函数,字符串等)没有函数。当你这样做的时候,它们仍然是从函数中某处调用的“构造函数”构造的。函数及其构造函数不仅是从类型创建新对象,而且还分配“prototype”属性、“proto”属性以及继承的 * prototype * 或子对象将使用的对象的实际树。
JavaScript中的对象有两种状态,“类型”和实际示例化的对象。这就是为什么“对象”与“const x = {}"创建的对象不一样。这就是为什么“类型”开始时与它的最终继承或原型不同。
看看这个!

// The Array type has a prototype of "Function.prototype"
alert(Object.prototype.toString.call(Array));// [object Function]

// But an instance of an Array object has a NEW prototype of "Array.prototype" that the function prototype's constructor created for the object!
const myarray = [];
alert(Object.prototype.toString.call(myarray));// [object Array]

后来呢?
结果是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继承属性的静态副本,而可以是您创建的全新对象!

let newPet;
function Pet() {
  this.fourlegs = true;
}

var Cat = {
  type : "cat"
}

var Dog = {
  type : "dog"
}

// We can see the prototype our constructor created for us
// and modify it as we like! Here we assigned it to an object
// which only means the prototype will merge "Cat" object's
// properties into the Pet.prototype.
Pet.prototype = Cat;

newPet = new Pet();
alert(newPet.type);// cat - inherited the Cat Object's properties in the prototype

Pet.prototype = Dog;

newPet = new Pet();
alert(newPet.type);// dog - inherited the Dog Object's properties in the prototype

alert(newPet.fourlegs);// true - this shows, even though you replace prototype, it ADDs the new types but does NOT erase the existing object properties! This must mean "prototype" is dynamically additive and rebuilt until the final "Pet" prototype is complete.

// Now change the "Pet.prototype" so all new objects have a new property.
Pet.prototype.furcolor = "white";
newPet = new Pet();
alert(newPet.furcolor);// "white"

// So you can see the "Pet.prototype" is dynamic, something you can tell the function constructor to modify!

相关问题