__proto__はconstructor.prototypeとどのように異なりますか?


163
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をどのようにチェックしますか?


30
このグラフ図は、プロトタイプとプロトの違いを理解するのに役立ちます。newtoyオブジェクトからプロトチェーンをたどることができ、newtoyからの3番目のプロトがnullである理由がわかります。
ビット

また、図からnewtoy.prototypeは等しくないためnewtoy.constructor.prototypenewtoy.constructor.prototypeというプロパティはありませんrating。同様newtoy.constructor.prototype.constructor.propertyに、というプロパティもありませんrating
ビット

最後のコメントの誤植:したがって、newtoy.constructor.prototype評価と呼ばれるプロパティがあります。同様newtoy.constructor.prototype.constructor.propertyに、評価と呼ばれるプロパティがあります。
ビット


1
@Royi Namir githubにjsVizをアップロードしました。こちらがデモサイトです。実際のコードがどれほどメンテナンスされていない(そしてダーティーである)か気にしないでください。私が永遠に触れたことのないその超古いプロジェクト。
ビット

回答:


210

私は最近これに頭を回そうとしているのですが、ついにこの「地図」を思いつきました。

http://i.stack.imgur.com/KFzI3.png ここに画像の説明を入力してください

私はこれを最初に作った人ではないことを知っていますが、それを見つけることを理解するのはもっと面白かった:-) とにかく、その後、私は例えば基本的に同じと思うこの別の図を見つけました:

JavaScriptオブジェクトのレイアウト

私にとって最も驚くべきことは、の代わりにをObject.__proto__指すことを発見したことですFunction.prototypeObject.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);

2
@utsainaとてもかっこいい。OPが投稿したコードの別のグラフィック表現を確認してください。そして、私たちの図は技術的な詳細に関しては一致していると思います。
ビット

43
理由Object.__proto__点にFunction.prototypeあるためであり、Object()それ自体では、空のオブジェクトをインスタンス化するネイティブ関数です。したがって、Object()関数です。他のすべての主要なネイティブ型の__proto__プロパティがを指してFunction.prototypeいることがわかります。ObjectFunctionStringNumber、およびArrayすべての継承関数のプロトタイプ。
スイベル2013年

@drodsou 2番目のリンクは素晴らしいです。今すぐチェックしてください;)mollypages.org/misc/js.mpいい説明:D
abhisekp

@Swivel "したがって、Object()は関数です"-Objectは関数であるということですか?なし()
giorgim

2
@GiorgiMoniava正解です。Objectそれ自体が関数です。callableを実行した結果Object(つまり、runningの戻り値Object())は関数ではありません。
2016

67

constructorは、prototype関数オブジェクトのプロパティが指すオブジェクトの事前定義[[DontEnum]]プロパティであり、最初は関数オブジェクト自体を指します。

__proto__ オブジェクトの内部[[Prototype]]プロパティ、つまり実際のプロトタイプと同等です。

new演算子を使用してオブジェクトを作成すると、その内部[[Prototype]]プロパティは、コンストラクター関数のprototypeプロパティが指すオブジェクトに設定されます。

これは、.constructorがに評価されることを意味します.__proto__.constructor。つまり、オブジェクトの作成に使用されるコンストラクター関数であり、学習したように、protoypeこの関数のプロパティは、オブジェクトの[[Prototype]]の設定に使用されました。

以下.constructor.prototype.constructorと同じです.constructor(これらのプロパティが上書きされていない限り)。詳細については、こちらをご覧ください。

__proto__が利用可能な場合は、オブジェクトの実際のプロトタイプチェーンをたどることができます。JavaScriptは深い継承階層用に設計されていないため、プレーンECMAScript3でこれを行う方法はありません。


3
その「ここ」のリンクがゴールドスタンダードです。完全な説明が必要な場合は、そこに移動してください。
リカルシン2012

.constructor.prototypeチェーンを使ったナイスキャッチ。私が見なかったが、私は、私のためにも不明であった.constructorに等しいです.__proto__.constructor。これは単に、コンストラクター関数とそのプロトタイプの間を循環することを意味します。
Johnny_D 2013年

30

JavaScriptのプロトタイプ継承は__proto__、各オブジェクトがその__proto__プロパティによって参照されるオブジェクトのコンテンツを継承しているという意味で、プロパティに基づいています。

このprototypeプロパティは、Functionオブジェクトのみ、およびnew演算子を使用してFunctionasコンストラクターを呼び出す場合にのみ特別です。この場合、作成されたオブジェクトの__proto__はコンストラクタに設定されFunction.prototypeます。

つまり、を追加するFunction.prototypeと、__proto__を参照しているすべてのオブジェクトが自動的に反映されますFunction.prototype

コンストラクタFunction.prototypeを別のオブジェクトで置き換えても、既存のオブジェクトのプロパティ更新されません__proto__

__proto__プロパティには直接アクセスしないでください。代わりにObject.getPrototypeOf(object)を使用してください。

最初の質問に答えるために__proto__prototype参考文献のカスタムダイアグラムを作成しましたが、残念ながら、stackoverflowでは「10レピュテーション未満」の画像を追加できません。多分別の時に。

[編集] ECMAScript仕様が内部オブジェクトを参照する方法[[Prototype]]である__proto__ので、図はの代わりに使用します。あなたがすべてを理解できることを願っています。

図を理解するのに役立ついくつかのヒントを次に示します。

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プロパティは作成されたオブジェクトには存在しないが、プロトタイプから継承されることに注意してください。

ここに画像の説明を入力してください


缶@xorcusあなたはこれを説明してください:new MyFunction()そのオブジェクトのインスタンスを作成し__proto__ているそのCTORプロトタイプを参照する必要がありMyFunction.prototype.ませんだから、なぜMyFunction.prototype.__proto__にreferesをObject.prototype?(私の最初のサンプルのように)その俳優のプロトタイプMyFunction.prototype(それMyFunction.prototypeがのインスタンスであることに注意してくださいMyfunction)を参照する必要があります
Royi Namir

@Royi Namir:MyFunction.prototypeはオブジェクトであるため、MyFunction.prototype .__ proto__はObject.prototypeを参照します。Object.prototypeはすべてのオブジェクトによって継承されます(通常、ここで継承のプロトタイプチェーンが終了します)。MyFunction.prototypeがMyFunctionのインスタンスであることに同意しません。obj instanceof MyFunction <=> MyFunction.prototype.isPrototypeOf(obj)<=> MyFunction.prototypeは、objプロトタイプチェーンに存在します。MyFunction.prototypeオブジェクトはそうではありません
xorcus

14

ObjectはイブでありFunction、アダムです。アダム(Function)は彼の骨(Function.prototype)を使用してイブ(Object)を作成します。次に、アダム(Function)を作成したのは誰ですか?-JavaScript言語の発明者:-)

utsainaの回答によると、もっと役立つ情報を追加したいと思います。

私にとって最も驚くべきことは、の代わりにをObject.__proto__ 指すことを発見したことですFunction.prototypeObject.prototype、それには正当な理由があると確信しています:-)

それはいけません。 Object.__proto__を指すべきではありませんObject.prototype。代わりに、のインスタンスObject oo.__proto__を指している必要がありますObject.prototype

(用語classinstanceJavaScript を使用したことをお詫びしますが、ご存知でしょう:-)

クラス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です。 ObjectFunction特別なだけですが、それらはまだクラスCatですが、通常のクラスです。

要素の問題として、Google Chrome JavaScriptエンジンでは、次の4です。

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

それらはすべて===他の3と(絶対的に等しい)で、その値は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

OK。では、誰がスペシャルfunction Empty() {}Function.prototype)を作成しますか?考えてみてください:-)


最後の1つを除いて、それに同意しfunction Empty() {}ます。Function.prototypeなどと等しいとは何を指しますか。Chromeコンソールで使用したコードは何ですか。
drodsou

2
あなたが指摘した最後の1つを修正しました。その価値はfunction Empty() {}Google Chromeにあります。コンソール出力も追加しました。
ピーターリー

すべての関数はinstanceof Functionであるため、すべての関数_ _proto_ _はFunction.prototypeから()を継承します。それはそれと同じくらい簡単です:)
xorcus

古いスレッドにコメントしてごめんね。しかし、それらは言語の発明者によって作成されたのでしょうか?
Patel Parth

6

あなたの理解の実際の問題がどこにあるのか、なぜ人々があなたを正さなかったのか、私には本当にわかりません。

これにより、問題を特定しやすくなります

だから何が起こっているのか見てみましょう:

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__

その前に、次の2つのことを覚えておいてください__proto__

  1. new演算子を使用してオブジェクトを作成すると、その内部[[Prototype]]/ proto__プロパティはprototypeconstructor function必要に応じてそのオブジェクトまたは「作成者」のproperty(1)に設定されます。

  2. JS —:Object.prototype.__proto__is 内でハードコードされていますnull

この2点を「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

いい?


2

すべての関数がプロトタイプを作成します。そして、その関数コンストラクターを使用してオブジェクトを作成すると、オブジェクトの__proto__プロパティがその関数のプロトタイプを指すようになります。


1
__proto__プロパティを言うつもりだったと思います。
demisx 2014

はい。オブジェクトのprotoプロパティを意味しました。この情報がお役に立てば幸いです。
Apoorv Nag

2

これらの数値がすべて圧倒的である場合は、プロパティの意味を見てみましょう。

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プロパティは機能のためにのみ利用可能です。

STH.constructor

上記のプロトタイプオブジェクトには、1つの-以外のプロパティはありませんconstructor。このプロパティは、プロトタイプオブジェクトを作成した関数を表します。

var toy = new Gadget();

作成するときにGadget機能を、我々は次のようにオブジェクトを作成した{constructor: Gadget}としても-のようなものではないというGadget.prototypeconstructorオブジェクトのプロトタイプを作成した関数を指す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 .__ proto__

一方でprototype機能のプロパティ固有のものです、__proto__それはに産むように、すべてのオブジェクトのために利用可能ですObject.prototype。オブジェクトを作成できる関数のプロトタイプを指します。

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

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

ここはtoy.__proto__ですGadget.prototypeGadget.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

0

短い答え:オブジェクトを作成したコンストラクター__proto__prototypeプロパティへの参照です。

JavaScriptのオブジェクト

JavaScriptオブジェクトは、0個以上のプロパティのコレクションの組み込み型です。プロパティは、他のオブジェクト、プリミティブ値、または関数を保持するコンテナーです。

JavaScriptのコンストラクタ

関数は通常のオブジェクト([[Call]]ECMA-262用語で実装)であり、呼び出し可能という追加機能を備えていますが、JavaScriptで別の役割を果たします。演算子を介して呼び出されると、コンストラクター(オブジェクトのファクトリー)になりますnew。したがって、コンストラクタは他の言語のクラスに大体類似しています。

すべてのJavaScript関数は、実際にはFunction組み込み関数オブジェクトのインスタンスであり、prototypeプロトタイプベースの継承と共有プロパティの実装に使用されるという特別なプロパティがあります。コンストラクター関数によって作成されたすべてのオブジェクトには、そのコンストラクターの値への暗黙的な参照(プロトタイプまたはと呼ばれ__proto__ます)がありますprototype

コンストラクターprototypeは、コンストラクターによって作成されたすべてのオブジェクトがそのオブジェクトへの参照を継承するため、オブジェクトを構築するための一種の設計図ですprototype

プロトタイプチェーン

オブジェクトは、内部プロパティ[[Prototype]]またはを介してプロトタイプを指定します__proto__。2つのオブジェクト間のプロトタイプ関係は継承に関するものです。すべてのオブジェクトは、そのプロトタイプとして別のオブジェクトを持つことができます。プロトタイプがnull値になる場合があります。

__proto__プロパティによって接続されたオブジェクトのチェーンは、プロトタイプチェーンと呼ばれます。オブジェクトのプロパティへの参照が作成される場合、その参照は、その名前のプロパティを含むプロトタイプチェーンの最初のオブジェクトで検出されたプロパティへの参照です。プロトタイプチェーンは、単一のオブジェクトであるかのように動作します。

この画像を参照してください(このブログから抜粋):

proto.jpg

オブジェクトのプロパティにアクセスしようとすると、JavaScriptはそのオブジェクトのプロパティの検索を開始し、そのプロトタイプ、プロトタイプのプロトタイプなどを使用して、プロパティが検出されるか__proto__、値が保持されるまで続けますnull

プロトタイプチェーンを使用するこのタイプの継承は、クラスチェーンを使用する他の言語との混乱を避けるために、委任と呼ばれることがよくあります。

はプロトタイプチェーンの最後にあるObjectため、ほとんどすべてのオブジェクトはのインスタンスですObject.prototype。しかし、Object.prototypeは価値を保持しているObjectので、インスタンスではありません。Object.prototype.__proto__null

次のnullようなプロトタイプでオブジェクトを作成することもできます。

var dict = Object.create(null);

そのようなオブジェクトは、リテラルオブジェクトよりも優れたマップ(辞書)です。そのため、このパターンはdictパターン(辞書のdict)ます。

注:を使用し{}て作成されたリテラルオブジェクトは、がへの参照であるObjectため、のインスタンスです。({}).__proto__Object.prototype


使用している引用文とアーティファクトのソースを引用してください。画像はgiamir.com/pseudoclasses-and-prototypal-inheritance-in-JSから取得されたようですが、著作権はありますか?
ベルジ

@Bergi画像の出典を引用しました。私が使用した引用のほとんどは、JS標準またはMDNから抽出されたものです
eigenslacker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.