__proto__VS。JavaScriptのプロトタイプ


785

この図は、すべてのオブジェクトにプロトタイプがあることを示しています。コンストラクター関数Fooには、__proto__Function.prototype という独自の関数もあり、その__proto__プロパティを介してObject.prototypeを再び参照します。したがって、繰り返しますが、Foo.prototypeはFooの明示的なプロパティであり、bおよびcオブジェクトのプロトタイプを参照します。

var b = new Foo(20);
var c = new Foo(30);

違いは何ですか__proto__とはprototype

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

図はdmitrysoshnikov.comから取られました



5
トップダウンかボトムアップかは好みの問題だと思います。私はこの方法を実際に好むので、何かがどこから来るのかを見つけるまで、ダイアグラムをたどることができます。
Mike Lippert、2014

1
JavaScriptがプロトタイプ継承を使用してy.constructorをy .__ proto __。constructorに解決する方法が好きです。Object.prototype .__ proto__がnullに設定された状態で、Object.prototypeがプロトタイプ継承チェーンの最上部に配置される方法も気に入っています。ダイアグラムが、プログラマーがオブジェクトを1.インスタンス、2。コンストラクター、3。新しいキーワードでインスタンス化されたときにこれらのインスタンスに関連付けるプロトタイプとしてオブジェクトをどのように考えるかを3列で概念的に視覚化する方法も気に入っています。
John Sonderson 2014年

この図は、youtube.com/ watch
v

そして今、私が答えを読んだので、実際に何が起こっているかについてクリスタルクリーンな(そして非WTFy)説明があるので、上記のビデオを本当に推薦する義務があると感じてください:)
mlvljr

回答:


766

__proto__メソッドを解決するためにルックアップチェーンで使用される実際のオブジェクトです。など prototypeでオブジェクト__proto__を作成するときにビルドに使用されるオブジェクトですnew

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

239
ああ!したがってprototype、インスタンス自体(または他のオブジェクト)では使用できず、コンストラクター関数でのみ使用できます。
rvighne 2014

43
@rvighne:prototypeそれらが由来しているので機能でのみ利用可能ですFunctionFunctionと、Objectしかし何かにそうではありません。ただし、__proto__どこでも使用できます。
Tarik

19
そう__proto__しながら、保存され、プロトタイプとして使用されている実際のオブジェクトであるMyconstructure.prototypeためだけの青写真で __proto__、実際のオブジェクトを保存してprotoypeとして使用Infactはあります。したがってmyobject.prototype、実際のオブジェクトのプロパティにはなりmyobject.__proto__ません。これは、コンストラクター関数が一時的なものであるため、外観を概説 するためです。
Alex_Nabu

9
__proto__オブジェクトのプロパティは、オブジェクトのコンストラクター関数のprototypeプロパティへのポインターであると言ってもよいでしょうか。つまりfoo .__ proto__ === foo.constructor.prototype
Niko Bellic

10
@Alex_Nabu違います。newCar.__proto__ IS Car.prototypeであり、のインスタンスではありませんCar.prototype。一方では、Car.protoype ISのインスタンスobjectCar.prototype与えものではありませんnewCar、それは単に、任意の性質や構造をIS次のobjectnewCarのプロトタイプチェーン。Car.prototype一時的なものではありませんobject。それはあるobjectの値として設定されている__proto__すべての新しいのプロパティobjectsが使用して作られたCarようconstructor。何かを青写真として考えたい場合は、新しい車の青写真objectと考えてください。Carobject
seangwright 2016

336

prototypeFunctionオブジェクトのプロパティです。これは、その関数によって構築されたオブジェクトのプロトタイプです。

__proto__プロトタイプを指すオブジェクトの内部プロパティです。現在の標準は同等のObject.getPrototypeOf(O)方法を提供していますが、事実上の標準です__proto__が高速です。

instanceof関数とprototypeオブジェクトの__proto__チェーンを比較することで関係を見つけることができ、を変更することでこれらの関係を解除できますprototype

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;

これPointはコンストラクター関数であり、オブジェクト(データ構造)を手続き的に構築します。myPoint構築されたオブジェクトされPoint()そうにPoint.prototypeに保存されますmyPoint.__proto__その時に。


2
また__proto__、オブジェクトのプロパティを変更すると、プロトタイプ検索が実行されるオブジェクトも変更されます。たとえば、メソッドのオブジェクトを関数として追加__proto__して、呼び出し可能なインスタンスオブジェクトのようなものを作成できます。
kzh、2014

myPoint .__ proto __。constructor.prototype == Point.prototype
Francisco

@kzh lol面白い結果が出ましたconsole.log(obj1.call) // [Function: call] obj1.call()// TypeError:obj1.callは関数ではありません。私がしましたobj.__proto__ = Function.__proto__
abhisekp

myFn.__proto__ = {foo: 'bar'}
kzh

私はあなたのポイントを持っていると思います。
ComicScrip

120

プロトタイププロパティは、関数が宣言されるときに作成されます。

例えば:

 function Person(dob){
    this.dob = dob
 }; 

Person.prototype上記の関数を宣言すると、プロパティが内部的に作成されます。新しいPerson()を使用して作成されたPersonインスタンスによって共有される多くのプロパティをPerson.prototypeに追加できます。

// adds a new method age to the Person.prototype Object.
Person.prototype.age = function(){return date-dob}; 

これはPerson.prototypeObjectデフォルトリテラルです(必要に応じて変更できます)。

を使用しnew Person()て作成されたすべてのインスタンスには、__proto__を指すプロパティがありますPerson.prototype。これは、特定のオブジェクトのプロパティを検索するためにトラバースするために使用されるチェーンです。

var person1 = new Person(somedate);
var person2 = new Person(somedate);

の2つのインスタンスを作成しますPerson。これらの2つのオブジェクトagePerson.prototypeasのメソッドを呼び出すことができますperson1.ageperson2.age

あなたの質問の上の画像でFooは、それがであることがわかります。Function Objectしたがって、それはへの__proto__リンクを持ち、Function.prototypeこれはのインスタンスでObjectあり、__proto__へのリンクを持っていますObject.prototype。プロトリンクは、ここを指す__proto__で終わります。Object.prototypenull

どのオブジェクトも__proto__、によってリンクされたプロトチェーン内のすべてのプロパティにアクセスできるため、プロトタイプ継承の基礎を形成します。

__proto__ プロトタイプチェーンにアクセスする標準的な方法ではありません。標準的ですが、同様のアプローチを使用します Object.getPrototypeOf(obj)

以下のコード instanceof演算子のは、より良い理解を提供します:

オブジェクトinstanceofクラス演算子はtrue、オブジェクトがクラスのインスタンスである場合に返されます。具体的にClass.prototypeは、そのオブジェクトのプロトチェーンで見つかった場合、オブジェクトはそのクラスのインスタンスです。

function instanceOf(Func){
  var obj = this;
  while(obj !== null){
    if(Object.getPrototypeOf(obj) === Func.prototype)
      return true;
    obj = Object.getPrototypeOf(obj);
  }
  return false;
}      

上記のメソッドは次のように呼び出すことができますinstanceOf.call(object, Class)。オブジェクトがクラスのインスタンスである場合にtrueを返します。


2
prototypeそもそもなぜオブジェクトが内部で作成されたのかと思っていました。静的メソッドを関数オブジェクト自体に単に割り当てることができます。例えばfunction f(a){this.a = a}; f.increment = function(){return ++this.a}prototypeオブジェクトにメソッドを追加するよりも、この方法が選ばれなかったのはなぜですか?これはf.__proto__ = g、gが基本クラスの場合に機能します。
abhisekp 2016

たぶん、prototypeオブジェクトは、排他的な機能のコンストラクタのプロパティは、関数コンストラクタオブジェクトに格納することができますので、共有するために選びだしました。
abhisekp

1
実際には、プロパティが削除されるとプロトタイプを区別する方法がないため、混乱instanceofを招きます。({}) instanceof Function === trueprototype
abhisekp 2016

@abhisekpこれはどういう意味ですか:「f .__ proto__ = g(gは基本クラス)の場合に機能します。」これに意味があるかどうかわかりませんが、プロパティとメソッドをそのように追加すると、newキーワードを使用してインスタンスを作成したときに、プロパティとメソッドがコピーされません。以上。
doubleOrt

67

それを考える良い方法は...

prototypeconstructor()関数によって使用されます。本当にそう呼ばれるべきだった"prototypeToInstall"であるので。

そして__proto__、オブジェクトに「インストールされたプロトタイプ」です(constructor()関数からオブジェクトに作成/インストールされたもの)


2
私はそれを賛成しましたが、おそらく反対の理由は、「コンストラクター()関数によってプロトタイプが使用されている」というステートメントが、コンストラクター以外の関数にはないように聞こえる可能性があるためです。 new ...で呼び出された場合、すべての関数がコンストラクターである可能性があることに注意してください
yoel halb

2
constructor()関数」と混同される可能性があるため、「関数」を「コンストラクタ関数」に変更してください__proto__.constructor()newキーワードが使用されたときに__proto __。constructorが実際には呼び出されないため、私はこれを重要だと考えています。
Alexander Gonchiy

1
プロトタイプはconstructor()関数で使用される」というステートメントは、重要な事実の一部のみを伝えていますが、読者にそれを全体の事実であると思わせるような方法で伝えています。プロトタイプは、その関数が将来どのように呼び出されるかに関係なく、Javascriptのすべての関数宣言に対して内部的に作成されます- 新しいキーワードの有無にかかわらず。宣言された関数のプロトタイプはオブジェクトリテラルを指します。
Yiling

62

説明するために関数を作成しましょう

 function a (name) {
  this.name = name;
 }

JavaScriptがこのコードを実行するprototypeaprototypeプロパティがに追加されます。プロパティは、2つのプロパティを持つオブジェクトです。

  1. constructor
  2. __proto__

だから私たちがするとき

a.prototype 戻る

     constructor: a  // function definition
    __proto__: Object

ご覧のconstructorとおり、関数aそのものであり__proto__、ルートレベルを指していますObject、JavaScriptのをます。

キーワードa付きの関数を使用するとどうなるか見てみましょうnew

var b = new a ('JavaScript');

JavaScriptがこのコードを実行すると、次の4つの処理が行われます。

  1. 新しいオブジェクト、空のオブジェクトを作成します// {}
  2. それを作成__proto__b、それを指すa.prototypeようにしますb.__proto__ === a.prototype
  3. 新しく作成されたオブジェクト(ステップ#1で作成された)をコンテキスト(this)として実行a.prototype.constructor(関数の定義a)するため、name'JavaScript'として渡されるプロパティ(thisに追加されます)は、新しく作成されたオブジェクトに追加されます。
  4. (手順1で作成された)で新しく作成されたオブジェクトを返すため、var bは新しく作成されたオブジェクトに割り当てられます。

追加a.prototype.car = "BMW"して実行すると b.car、出力「BMW」が表示されます。

これは、JavaScriptがcarプロパティを検索するこのコードを実行したときに、使用されたJavaScript (ステップ#2で「a.prototype」を指すように作成された)がb見つからず、プロパティb.__proto__が見つかったcarため、「BMW」を返すためです。


2
1. constructor戻りませんa()!戻りますa。2. JavaScriptのルートオブジェクトではなくを__proto__返しますObject.prototype
doubleOrt

1
これは素晴らしい答えです!
john-raymon

+1これは、どのプロトタイプが実際にIS(2つのプロパティを持つオブジェクト)であり、Javascriptが各コードを実行する方法を説明する最良の答えです。この情報を入手するのは驚くほど難しいです。
java-addict301

53

プロトタイプVS。__proto__VS。[[プロトタイプ]]

関数を作成すると、プロトタイプと呼ばれるプロパティオブジェクトが自動的に作成され(自分で作成しなかったconstructor)、関数オブジェクト()にアタッチされます。
:この新しいプロトタイプオブジェクトも、ネイティブJavaScriptオブジェクトをポイントするか、ネイティブJavaScriptオブジェクトへの内部プライベートリンクを持っています。

例:

function Foo () {
    this.name = 'John Doe';
}

// Foo has an object property called prototype.
// prototype was created automatically when we declared the function Foo.
Foo.hasOwnProperty('prototype'); // true

// Now, we can assign properties and methods to it:
Foo.prototype.myName = function () {
    return 'My name is ' + this.name;
}

キーワードをFoo使用せずに新しいオブジェクトを作成する場合new、基本的に(特に)前に説明した関数のプロトタイプへの内部リンクまたはプライベートリンクを持つ新しいオブジェクトを作成していますFoo

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true


その関数のオブジェクトへ のプライベートリンケージは、ダブルブラケットプロトタイプまたはと呼ばれます[[Prototype]]。多くのブラウザは、それと呼ばれるそれへのパブリックリンケージを提供しています__proto__

具体的に__proto__は、実際にはネイティブJavaScriptオブジェクトに属するゲッター関数です。thisバインディングが何であれ、内部プライベートプロトタイプリンケージを返します([[Prototype]]ofを返しますb)。

b.__proto__ === Foo.prototype // true

の開始に注意する価値ECMAScript5があります。getPrototypeOfメソッドを使用して内部プライベートリンケージを取得することもできます。

Object.getPrototypeOf(b) === b.__proto__ // true


注:この回答は、新しいオブジェクトまたは新しいコンストラクタを作成するプロセス全体を対象とするものではありませんが__proto__prototypeとは何か、および[[Prototype]]それがどのように機能するかを理解するのに役立ちます。


2
@Taurus、ヘッダーをクリックすると、ECMAScript仕様ドキュメントが表示されます。詳細については、セクション9(通常オブジェクトとエキゾチックオブジェクトの動作)をご覧ください。
Lior Elrom 2017

私はここでいくつかの間違いがあると思います:_関数のプロトタイプFooへの内部リンクまたはプライベートリンクを持つ新しいオブジェクト?意味:関数Fooのプロトタイプへの内部リンクまたはプライベートリンクを持つ新しいオブジェクト
Koray Tugay

1
@KorayTugayに感謝!はい、スペルを間違えました:) +1
Lior Elrom

31

上記の素晴らしい答えに加えて、それを少し明確にするために:

function Person(name){
    this.name = name
 }; 

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

インスタンスに__proto__がありクラスにプロトタイプがあります。


12

JavaScriptでは、関数をコンストラクターとして使用できます。つまり、新しいキーワードを使用してオブジェクトからオブジェクトを作成できます。すべてのコンストラクター関数には、組み込みのオブジェクトがチェーンされています。この組み込みオブジェクトはプロトタイプと呼ばれます。Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

プロトタイプ図

  1. 最初にコンストラクタを作成しました:function Foo(){}。明確に言うと、Fooは単なる別の機能です。しかし、新しいキーワードを使用して、そこからオブジェクトを作成できます。それがコンストラクタ関数と呼ばれる理由です

  2. すべての関数には、プロトタイププロパティと呼ばれる一意のプロパティがあります。したがって、コンストラクター関数にFooは、そのプロトタイプを指すプロトタイププロパティがありますFoo.prototype(図を参照)。

  3. コンストラクター関数自体は、[[Function]]コンストラクターと呼ばれるシステムコンストラクターのインスタンスである関数です。したがってfunction Foo、[[Function]]コンストラクターによって構築されていると言えます。だから、__proto__私たちのFoo functionあるコンストラクタのプロトタイプへの意志ポイントFunction.prototype

  4. Function.prototype自体は、と呼ばれる別のシステムコンストラクターから構築されたオブジェクトにすぎません[[Object]]。つまり、[[Object]]のコンストラクタですFunction.prototype。つまり、Function.prototypeはのインスタンスです[[Object]]。だから、__proto__Function.prototypeへのポイントObject.prototype

  5. Object.prototypeプロトタイプチェーンで最後に立っている男です。つまり、建設されていません。システムにはすでに存在しています。したがって、その__proto__ポイントはnullです。

  6. 次に、のインスタンスについて説明しますFoo。を使用してインスタンスを作成すると、のインスタンスでnew Foo()ある新しいオブジェクトが作成されますFoo。つまりFoo、これらのインスタンスのコンストラクタです。ここでは、2つのインスタンス(xとy)を作成しました。__proto__したがって、xとyのはを指しFoo.prototypeます。


明確にするために:インスタンスには.prototypeプロパティがありませんか?コンストラクター関数だけが正しいですか?...したがって、インスタンスとそのコンストラクター関数の違いは次のとおりです。コンストラクター関数は両方とも1. proto 2. .prototypeオブジェクトを持っていますが、インスタンスには.__ proto__プロパティしかありません...正しいですか?
Shaz

@Shazあなたは正しい。インスタンスはプロトを使用して、コンストラクター関数のプロトタイププロパティにアクセスします。
AL-zami

しかし、なぜあなたが書くときにそれがなぜなのか:var car = Object.create(Vehicle); car .__ proto__ = Vehicleを取得しますが、Vehicle.prototypeを指すcar.prototypeプロパティも取得しますか?
Shaz

@shaz状況を視覚化できるように、jsfiddleを提供できますか?
AL-zami、

1
ここで、car.prototypeは継承されたプロパティです。車は車両の機能から「プロトタイプ」プロパティを継承します。したがって、car.prototype === vehicle.prototypeです。「プロトタイプ」プロパティは、車両のプロパティです。車はそのプロトタイプチェーンを通してそれにアクセスできます。これで混乱が解消されることを願っています
AL-zami

8

概要:

__proto__オブジェクトのプロパティは、オブジェクトprototypeのコンストラクター関数のにマップされるプロパティです。言い換えると:

instance.__proto__ === constructor.prototype // true

これはprototype、オブジェクトのチェーンを形成するために使用されます。prototypeチェーンは、オブジェクトのプロパティのルックアップメカニズムです。オブジェクトのプロパティにアクセスすると、JavaScriptはまずオブジェクト自体を調べます。プロパティがそこに見つからない場合、それはまでずっと上昇しますprotochainそれが見つかるまで(または見当たらない)まで

例:

function Person (name, city) {
  this.name = name;
}

Person.prototype.age = 25;

const willem = new Person('Willem');

console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor

console.log(willem.age); // 25 doesn't find it at willem object but is present at prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

最初のログの結果はですtrue。これは、前述のように__proto__、コンストラクターによって作成されたインスタンスのプロパティがprototypeプロパティがコンストラクターのプロパティをいるためです。JavaScriptでは、関数もオブジェクトです。オブジェクトはプロパティを持つことができ、関数のデフォルトプロパティはプロトタイプと呼ばれる1つのプロパティです。

次に、この関数をコンストラクター関数として使用すると、この関数からインスタンス化されたオブジェクトは、というプロパティを受け取ります__proto__。そして、この__proto__プロパティはprototype、コンストラクター関数のプロパティを参照します(デフォルトでは、すべての関数にあります)。

なぜこれが便利なのですか?

JavaScriptには、「プロトタイプ継承」Objectsと呼ばれるプロパティを検索するメカニズムがあります。基本的には次のようになります。

  • まず、プロパティがオブジェクト自体にあるかどうかがチェックされます。その場合、このプロパティが返されます。
  • プロパティがオブジェクト自体に配置されていない場合は、「プロトチェーンを登る」ことになります。基本的には、__proto__プロパティによって参照されるオブジェクトを調べます。そこで、によって参照されるオブジェクトでプロパティが使用可能かどうかをチェックし__proto__ます。
  • プロパティが__proto__オブジェクトに配置されていない場合は、オブジェクトまで__proto__チェーンを登っていきObjectます。
  • オブジェクトとそのprototypeチェーンのどこにもプロパティが見つからない場合は、を返しundefinedます。

例えば:

function Person (name) {
  this.name = name;
}

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);


7

私はたまたまYou Do n't Know JS:this&Object Prototypesからプロトタイプを学んでいます。これは、下のデザインを理解し、非常に多くの誤解を明らかにするための素晴らしい本です(そのため、継承やなどの使用を避けようとしていinstanceofます)。

しかし、私は人々がここで尋ねたのと同じ質問があります。いくつかの答えは本当に役に立ち、啓発的です。私も私の理解を共有したいと思います。


プロトタイプとは何ですか?

JavaScriptのオブジェクトには、仕様でとして示されている内部プロパティがあり[[Prototype]]、これは単に別のオブジェクトへの参照です。ほとんどすべてのオブジェクトには非null、作成時にこのプロパティの値。

オブジェクトのプロトタイプを取得するにはどうすればよいですか?

__proto__またはを介してObject.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype

とはprototype

prototype関数の特殊なプロパティとして自動的に作成されるオブジェクトであり、委任(継承)チェーン(別名プロトタイプチェーン)を確立するために使用されます。

私たちは関数を作成するとaprototype自動的に特別なプロパティとして作成されたaとように機能コードが保存されますconstructorprototype

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true

このプロパティは、関数オブジェクトのプロパティ(メソッドを含む)を格納する場所と考えたいです。それが、JSのユーティリティ関数が、、のようArray.prototype.forEach()に定義されている理由でもありますFunction.prototype.bind()Object.prototype.toString().

なぜ関数の特性を強調するのですか?

{}.prototype // undefined;
(function(){}).prototype // Object {constructor: function}

// The example above shows object does not have the prototype property.
// But we have Object.prototype, which implies an interesting fact that
typeof Object === "function"
var obj = new Object();

だから、AraryFunctionObjectすべての機能があります。これはJSに対する私の印象を新たにすることを認めるべきです。JSでは関数が一流の市民であることは知っていますが、関数に基づいて構築されているようです。

違いは何だ__proto__とはprototype

__proto__参照は、すべてのオブジェクトでその[[Prototype]]プロパティを参照するように機能します。

prototype関数の特別なプロパティとして自動的に作成されるオブジェクトです関数オブジェクトのプロパティ(メソッドを含む)を格納するために使用されるオブジェクトです。

これら2つを使用して、プロトタイプチェーンを精神的に計画することができます。この写真のように説明します:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true

7

 JavaScriptプロトタイプvs __prototype__

'use strict'
function A() {}
var a = new A();
class B extends A {}
var b = new B();
console.log('====='); // =====
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true

JavaScriptでは、すべてのオブジェクト(関数もオブジェクトです!)には__proto__プロパティがあり、プロパティはそのプロトタイプへの参照です。

newコンストラクターで演算子を使用して新しいオブジェクトを作成すると、新しいオブジェクトの__proto__プロパティはコンストラクターのprototypeプロパティで設定され、コンストラクターは新しいオブジェクトによって呼び出されます。このプロセスでは、「this」は新しいオブジェクトへの参照になりますコンストラクタスコープで、最終的に新しいオブジェクトを返します。

コンストラクタのプロトタイプは__proto__プロパティであり、コンストラクタのprototypeプロパティはnew演算子と連動します。

コンストラクタは関数である必要がありますが、関数がprototypeプロパティを持っていても、必ずしもコンストラクタであるとは限りません。

プロトタイプチェーンは、実際には__proto__そのプロトタイプを参照するオブジェクトのプロパティであり、プロトタイプの__proto__プロパティはプロトタイプのプロトタイプを参照し、以下同様に、__proto__null を参照するオブジェクトのプロトタイプのプロパティを参照します。

例えば:

console.log(a.constructor === A); // true
// "a" don't have constructor,
// so it reference to A.prototype by its ``__proto__`` property,
// and found constructor is reference to A

[[Prototype]]そして、__proto__プロパティは、実際には同じものです。

ObjectのgetPrototypeOfメソッドを使用して、何かのプロトタイプを取得できます。

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

私たちが作成した関数はすべて、new演算子を使用してオブジェクトを作成するために使用できるため、それらの関数の誰もがコンストラクターになることができます。


6

それを理解する別の良い方法:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.prototype; Object.prototype in return is what foo.__proto__ links to. 
*/
console.log(foo.constructor.prototype === foo.__proto__);
// this proves what the above comment proclaims: Both statements evaluate to true.
console.log(foo.__proto__ === Object.prototype);
console.log(foo.constructor.prototype === Object.prototype);

IE11 __proto__がサポートされた後のみ。IE9などの以前のバージョンでは、を使用してconstructorを取得できました__proto__


私がそれを逆に書くのはそれだけです:foo .__ proto__ === foo.constructor.prototype
epeleg

6

プロトタイプ

プロトタイプは関数のプロパティです。これは、新しいキーワードでその(コンストラクター)関数を使用してオブジェクトを作成するための青写真です。

__proto__メソッド、プロパティを解決するためにルックアップチェーンで使用されます。オブジェクトが作成されると(新しいキーワードでコンストラクター関数を使用)、__proto__(コンストラクター)Function.prototypeに設定されます

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype

これが混乱を解消するための私の(架空の)説明です。

関数に関連付けられた架空のクラス(青写真/クーッキーカッター)があるとします。その架空のクラスは、オブジェクトをインスタンス化するために使用されます。prototype架空のクラスに物を追加するための拡張メカニズム(C#の拡張メソッド、またはSwift拡張機能)です。

function Robot(name) {
    this.name = name;
}

上記は次のように想像できます。

// imaginary class
class Robot extends Object{

    static prototype = Robot.class  
    // Robot.prototype is the way to add things to Robot class
    // since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype

    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 

そう、

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

prototypeRobotにメソッドを追加します。

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};
// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

上記はRobotクラスの拡張と考えることができます:

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

次に

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

    // added by prototype (as like C# extension method)
    function move(x, y){ 
        Robot.position.x = x; Robot.position.y = y
    };
}

__proto__とプロトタイプのより一貫した名前をまだ考えています。多分プロトタイプと継承?
ドミトリー

私は言うだろう、prototype__proto__の両方を避けるべきです。今は授業があり、OOPが好きです。
Hassan Tareq 2018

問題は、クラスが比較的新しく、Microsoft JScript(Cで作業するときに便利で、常に存在する迅速でダーティなスクリプトエンジンが必要)などの本当に便利なエンジン、およびnashorn javascript(すべてに付属)によってサポートされていないことです。 jjsの下での新しいJavaインストールは、Javaを常に再コンパイルする必要がない純粋な動的環境に配置するための優れた方法です。問題は、クラスが砂糖だった場合、それは問題にはなりませんが、そうではありません。それは、古いjsバージョンではそれらなしでは不可能なことを提供します。「関数」を拡張するようなものです。
ドミトリー

最終的にはサポートを受けます。私はバックエンド開発者なので、問題はありません。jsでコーディングすることはほとんどありません。
Hassan Tareq 2018

そして、静的メンバーの追加/静的メンバーの親からの削除が子に気付かれる方法で継承します(私はObject.assign / __ proto __ / getPrototypeOfを提供しないJScriptで行う方法を考えることができないので、ルートObject.prototypeをいじる必要があります)
Dmitry

4

簡単に言えば:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true

これにより、タイプXのオブジェクトがインスタンス化された後、プロパティをX.prototypeにアタッチできます。これらのオブジェクトは、JavaScriptエンジンがプロトタイプチェーンをたどるために使用する__proto__参照を通じて、これらの新しいプロパティに引き続きアクセスできます。


4

プロトタイプまたはObject.prototypeは、オブジェクトリテラルのプロパティです。これは、プロトタイプチェーンに沿ってさらにプロパティまたはメソッドを追加するためにオーバーライドできるObjectプロトタイプオブジェクトを表します。

__proto__は、アクセスされるオブジェクトの内部プロトタイプを公開するアクセサープロパティ(getおよびset関数)です。

参照:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
  2. http://www.w3schools.com/js/js_object_prototypes.asp

  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto


Object.prototypeはオブジェクトリテラルのプロパティではないため、出力しようとすると{}.prototype未定義が返されます。ただし、{}.__proto__を返すを介してアクセスできますObject.prototype
doubleOrt

3

わかりました、私は遅れていますが、簡単にしてみましょう。

関数があるとしましょう

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);

Foo関数には、プロトタイプオブジェクトがリンクされます。したがって、JavaScriptで関数を作成するときは常に、常にプロトタイプオブジェクトがリンクされています。

次に、関数Fooを使用して2つのオブジェクトを作成します。

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);
  1. これで、オブジェクトaとオブジェクトbの2つのオブジェクトができました。どちらもコンストラクタFooを使用して作成されます。コンストラクタはここでの言葉にすぎないことを覚えておいてください。
  2. オブジェクトaとbの両方にメッセージプロパティのコピーがあります。
  3. これら2つのオブジェクトaおよびbは、コンストラクターFooのプロトタイプオブジェクトにリンクされています。
  4. オブジェクトaおよびbでは、すべてのブラウザーでprotoプロパティを使用してFooプロトタイプにアクセスでき、IEではObject.getPrototypeOf(a)またはObject.getPrototypeOf(b)を使用できます

今、Foo.prototype、a。proto、およびb。proto allは同じオブジェクトを表します。

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;

上記のすべてがtrueを返します。

ご存じのとおり、JavaScriptではプロパティを動的に追加できます。オブジェクトにプロパティを追加できます

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 

ご覧のとおり、Foo.prototypeにGreet()メソッドを追加しましたが、aとb、またはFooを使用して構築された他のオブジェクトからアクセスできます。

a.Greet()の実行中、JavaScriptは最初にプロパティリストのオブジェクトa内のGreetを検索します。見つからない場合は、aのプロトチェーンで上がります。以来。protoとFoo.prototypeは同じオブジェクトです。JavaScriptはGreet()メソッドを見つけて実行します。

プロトタイプとプロト が少し簡略化されたことを願っています。


3

説明例:

function Dog(){}
Dog.prototype.bark = "woof"

let myPuppie = new Dog()

現在、myPupppieにはDog.prototype __proto__を指すプロパティがあります。

> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}

myPuppieにはプロトタイププロパティはありません。

> myPuppie.prototype
>> undefined

つまり、__proto__mypuppieのは、このオブジェクトのインスタンス化に使用されたコンストラクター関数の.prototypeプロパティへの参照です(現在のmyPuppieオブジェクトには、この__proto__オブジェクトへの「委任先」関係があります)。一方、myPuppieの.prototypeプロパティはありません(なぜなら、設定しませんでした)。

ここMPJによる良い説明: プロト vsプロトタイプ-JavaScriptでのオブジェクト作成


3

私は自分のために、次のコードスニペットを表す小さな図面を作成しました。

var Cat = function() {}
var tom = new Cat()

__proto__とプロトタイプを理解する

私は古典的なOOの背景を持っているので、この方法で階層を表すことは役に立ちました。この図を読みやすくするために、画像内の長方形をJavaScriptオブジェクトとして扱います。そして、はい、関数もオブジェクトです。;)

JavaScriptのオブジェクトにはプロパティがあり__proto__、それらはその1つにすぎません。

このプロパティの背後にある考え方は、(継承)階層内の祖先オブジェクトを指すことです。

JavaScriptのルートオブジェクトはでObject.prototypeあり、他のすべてのオブジェクトはこのオブジェクトの子孫です。__proto__ルートオブジェクトのプロパティはですnull。これは、継承チェーンの終わりを表します。

これprototypeは関数のプロパティです。Cat関数であるが、また、FunctionおよびObject(ネイティブ)関数です。tomは関数ではないため、このプロパティはありません。

このプロパティの背後にある考え方は、構築で使用されるオブジェクトを指すnewことです。つまり、その関数でオペレーターを呼び出すときです。

プロトタイプオブジェクト(黄色の四角形)にはconstructor、それぞれの関数オブジェクトを指す別のプロパティが あります。簡潔にするため、これは表示されていません。

実際、を使用してtomオブジェクトを作成するとnew Cat()、作成されたオブジェクトの__proto__プロパティprototypeは、コンストラクター関数のオブジェクトに設定されます。

最後に、この図を少し試してみましょう。次のことが当てはまります。

  • tom.__proto__プロパティはと同じオブジェクトを指しますCat.prototype

  • Cat.__proto__ポイントFunction.prototypeだけのようなオブジェクト、Function.__proto__およびObject.__proto__行います。

  • Cat.prototype.__proto__tom.__proto__.__proto__同じオブジェクトを指し、それはObject.prototypeです。

乾杯!


とてもよく説明されました!
StackOverflow UI

@theshinylight、tom.__proto__そしてCat.prototype厳密に等しいので、tom.__proto__ === Cat.prototype そして Cat.prototype === tom.__proto__、本当です。では、画像の矢印はどういう意味ですか?
aXuser264

黒い矢印(参照している場合)は、オブジェクトのプロパティ以外は特に意味がありません。オブジェクトのprototypeプロパティも同様ですCat(質問から)。
theshinylight

2

定義

(括弧()内の数字は、以下に記述されているコードへの「リンク」です)

prototype-以下から構成されるオブジェクト
=>この特定のConstructorFunction.prototype(5)の関数(3)各オブジェクトからアクセス可能な(4)このコンストラクター関数を介して作成または作成される(1)
=>コンストラクター関数自体(1 )
=> __proto__この特定のオブジェクト(プロトタイプオブジェクト)

__proto__(dandor proto?)-特定のコンストラクター関数(1)によって作成されたオブジェクト(2)と、そのコンストラクターのプロトタイプオブジェクトのプロパティ(5)の間のリンク。これにより、作成された各オブジェクト(2)がプロトタイプの関数にアクセスできるようになります。およびメソッド(4)(__proto__JSのすべてのオブジェクトにデフォルトで含まれています)

コードの明確化

1。

    function Person (name, age) {
        this.name = name;
        this.age = age;} 

2。

    var John = new Person(‘John’, 37);
    // John is an object

3。

    Person.prototype.getOlder = function() {
        this.age++;
    }
    // getOlder is a key that has a value of the function

4。

    John.getOlder();

5。

    Person.prototype;

1

私は4年生の説明をしてみます:

物事は非常に簡単です。A prototypeは、何かを構築する方法の例です。そう:

  • 私は私functionと同じような新しいオブジェクトを構築していますprototype

  • 私は、object私は自分__proto__の例を使用して構築されました

証明

function Foo() { }

var bar = new Foo()

// `bar` is constructed from how Foo knows to construct objects
bar.__proto__ === Foo.prototype // => true

// bar is an instance - it does not know how to create objects
bar.prototype // => undefined

1
いいえ、どちらprototypeも、__proto__オブジェクトを作成するための青写真などとしていつでも使用されません。これはぼやけたclass構文によって導入された神話であり、その前身です。回答投稿が言うように、それはルックアップチェーンと一緒に使用されるprototypeことを特定する場合にのみconstructor使用されますnew(これは、私を含む多くのユーザーを混乱させる、分類されるふりをするメカニズムの一部です)。
クリストフケーリン2017

最初のポイントは、「私は関数であり、プロトタイプに委任する新しいオブジェクトを構築すること」であるべきです
Nitin Jadhav

1

作成するすべての関数にはと呼ばれるプロパティがありprototype、空のオブジェクトとしての生活から始まります。このプロパティは、この関数をコンストラクター関数として使用するまで、つまり「new」キーワードを使用するまで役に立ちません。

これは__proto__、オブジェクトのプロパティと混同されることがよくあります。一部は混乱する可能prototype性があり、オブジェクトのプロパティがそれらをオブジェクトのプロトタイプにする可能性があることを除いて。しかし、これは事実ではありません。関数コンストラクターから作成されたオブジェクトのprototypeを取得するために使用されます__proto__

上記の例では:

function Person(name){
    this.name = name
}; 

var eve = new Person("Eve");

console.log(eve.__proto__ == Person.prototype) // true
// this is exactly what prototype does, made Person.prototype equal to eve.__proto__

私はそれが理にかなっていると思います。


1
prototype__proto__オブジェクトのの作成には使用されません。__proto__にアクセスすると、prototypeオブジェクトへの参照が提供されるだけです。
doubleOrt

1

__proto__静的メソッドの使用についてはどうですか?

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined

それがまさに「JavaScriptでの__proto__VS. 」prototypeに対する答えなのです。
Andreas

Foo.collection.push(this)Foo.count ++についてそれは良いですか、それとも何ですか
Selva Ganapathi

1

(function(){ 
      let a = function(){console.log(this.b)};
      a.prototype.b = 1;
      a.__proto__.b = 2;
      let q = new a();
      console.log(a.b);
      console.log(q.b) 
    })()

このコードを試して理解してください


1

典型的な連鎖に使用されるオブジェクトは1つだけです。このオブジェクトには明らかに名前と値__proto__があります。はその名前でありprototype、その値です。それで全部です。

さらに理解しやすくするために、この投稿の上部にある図(dmitry soshnikovによる図)を見てください。値__proto__以外のものへのポイントは決して見つかりませんprototype

要点はこれです。__proto__プロトタイプオブジェクトを参照する名前でprototypeあり、実際のプロトタイプオブジェクトです。

それは言っているようなものです:

let x = {name: 'john'};

xオブジェクト名(ポインター)であり{name: 'john'}、実際のオブジェクト(データ値)です。

注:これは、それらが高レベルでどのように関連しているかについての非常に単純化されたヒントです。

更新:よりわかりやすくするための簡単な具体的なJavaScriptの例を次に示します。

let x = new String("testing") // Or any other javascript object you want to create

Object.getPrototypeOf(x) === x.__proto__; // true

これは、Object.getPrototypeOf(x)がの実際の値x(そのプロトタイプ)を取得したときに__proto__xが指しているものとまったく同じであることを意味します。したがって、__proto__は実際にのプロトタイプを指していxます。したがって、(のポインタ)を__proto__参照し、(そのプロトタイプ)の値です。xxprototypex

私はそれが今少し明確であることを望みます。


1

これは、プロトタイプの継承を理解したい人にとって重要な質問です。私が理解しているところによると、関数はプロトタイプオブジェクトを定義上持っているため、オブジェクトが関数からnewで作成されると、デフォルトでプロトタイプが割り当てられます。

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]

newなしで、つまり関数から明示的に通常のオブジェクトを作成する場合、オブジェクトにはプロトタイプはありませんが、プロトタイプを割り当てることができる空のプロトがあります。

var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

Object.createを使用して、オブジェクトを明示的にリンクできます。

// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`

0

__proto__構築するベースとコンストラクprototypeター関数です。例:function human(){}has は、コンストラクター関数の新しいインスタンスでprototype共有__proto__されます。詳細はこちら


@Derick Daniel:なぜこれに反対票を投じたのかはわかりませんが、あなたが行った編集は私が伝えようとしていたことではありませんでした。より多くのクリアランスのためにそれをさらに編集しました:)。
Jyoti Duhan

ジョティ、私はあなたの回答に反対票を投じなかった、誰か他の人が投票した、私はそれを編集した:)
フリーランサー

0

これは正しく述べて

__proto__メソッドなどを解決するためにルックアップチェーンで使用される実際のオブジェクトです。プロトタイプは、__proto__newでオブジェクトを作成するときにビルドに使用されるオブジェクトです 。

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

さらに__proto__、関数コンストラクターを使用して作成されたオブジェクトのプロパティは、それぞれのコンストラクターのプロトタイププロパティが指すメモリ位置を指すことに注意してください。

コンストラクター関数のプロトタイプのメモリ位置を変更して__proto__も、派生オブジェクトは引き続き元のアドレス空間を指しています。したがって、継承チェーンで共通のプロパティを使用できるようにするには、プロパティを再初期化する(メモリアドレスを変更する)のではなく、常にプロパティをコンストラクター関数prototypeに追加します。

次の例を考えてみます。

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25

-1

私の理解は:__proto__とプロトタイプはすべてプロトタイプチェーンテクニックで提供されます。違いは、アンダースコア(__proto__など)で名前が付けられた関数は、明示的に呼び出される開発者向けではありません。言い換えれば、それらは継承などの一部のメカニズムのためだけのものです。それらは「バックエンド」です。ただし、アンダースコアなしで名前が付けられた関数は明示的に呼び出されるように設計されており、「フロントエンド」です。


3
to __proto__prototypeには、命名規則だけではありません。同じオブジェクトを指す場合としない場合があります。@zyklusの回答を参照してください。
demisx 2014

1
もちろん、あなたが言った@demisxは正しいですが、私の意見は、機能のコントラストを明らかにした名前の違いです。
Beicai 2014年

特に、他の良い答えが以前に提供されている場合は特に、「理解どおり」と述べるだけでは十分ではありません...
ProfNandaa

-3

!!!これは世界で最高の説明です!!!!!

var q = {}
var prototype = {prop: 11}

q.prop // undefined
q.__proto__ = prototype
q.prop // 11

関数コンストラクタでは、JavaScriptエンジンはq.__proto__ = prototypeを書き込んnew Classだときにこれを自動的に呼び出し、__proto__プロップセットに入れます。Class.prototype

function Class(){}
Class.prototype = {prop: 999} // set prototype as we need, before call new

var q = new Class() // q.__proto__ = Class.prototype
q.prop // 999

楽しい %)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.