JavaScript .prototypeはどのように機能しますか?


2041

私はそれを動的プログラミング言語に取り入れているわけではありませんが、JavaScriptコードの公正な共有を書きました。このプロトタイプベースのプログラミングに頭を悩ませたことはありません。

var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

昔、人と話し合ったことはよく覚えていますが(自分が何をしているのかよくわかりません)、クラスの概念はありません。それは単なるオブジェクトであり、それらのオブジェクトのインスタンスはオリジナルのクローンですよね?

しかし、JavaScriptのこの「.prototype」プロパティの正確な目的は何ですか?オブジェクトのインスタンス化とどのように関連していますか?

更新:正しい方法

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

また、これらのスライドは本当に役に立ちました。


78
John Resigには、関数のプロトタイプに関するいくつかのスライドがあり、件名を調べるときに役立ちました(コードを変更して何が起こるかを確認することもできます...)http://ejohn.org/apps/learn/#64
ジョンフォスター

5
この質問を参考にするための素晴らしい参考資料は、ジョンのサイトが変更されてリンクが利用できなくなった場合に備えて、ジョンのサイトからのコメントの一部を回答に記載することです。いずれにしても+1で助けてくれました。
クリス

95
John ResigのJavaScript忍者スライド#64へのリンクの+1 。そこから始まって本当に助かりましたし、プロトタイプを正しく理解している気がします。
有料オタク2012年

4
プロトタイプを適用するために機能オブジェクトが本当に必要ですか?はいの場合はなぜですか?
Anshul 2013

6
これは役立つかもしれません:webdeveasy.com/javascript-prototype
Naor

回答:


1007

すべてのJavaScriptオブジェクトは、内部の「スロット」があると呼ばれ[[Prototype]]、その値のいずれかnullobject。スロットは、JavaScriptエンジンの内部にあるオブジェクトのプロパティであり、記述したコードから隠されていると考えることができます。角括弧[[Prototype]]は意図的なものであり、内部スロットを示すECMAScript仕様の規則です。

[[Prototype]]オブジェクトのが指す値は、通称「そのオブジェクトのプロトタイプ」と呼ばれます。

ドット(obj.propName)またはブラケット(obj['propName'])表記を使用してプロパティにアクセスし、オブジェクトにそのようなプロパティがない場合(つまり、を介してチェック可能な独自のプロパティobj.hasOwnProperty('propName'))、ランタイムは参照されているオブジェクトでその名前のプロパティを検索します[[Prototype]]代わりに。に[[Prototype]] そのようなプロパティがない場合は[[Prototype]]、順番にチェックされます。このようにして、元のオブジェクトのプロトタイプチェーンは、一致が見つかるか、またはその最後に到達するまで処理されます。プロトタイプチェーンの一番上がnull価値です。

最新のJavaScript実装[[Prototype]]では、次の方法でへの読み取りおよび/または書き込みアクセスが可能です。

  1. newオペレータ(コンストラクタ関数から返されるデフォルトのオブジェクトに設定しプロトタイプチェーン)
  2. extendsキーワードは、(クラス構文を使用している場合、プロトタイプチェーンを構成します)
  3. Object.create指定された引数を[[Prototype]]結果のオブジェクトのとして設定し、
  4. Object.getPrototypeOfおよびObject.setPrototypeOf(オブジェクト作成[[Prototype]] 後の取得/設定)、および
  5. 名前が付けられた標準化されたアクセサ(つまり、getter / setter)プロパティ__proto__(4と同様)。

Object.getPrototypeOfそしてObject.setPrototypeOf上好ましい__proto__の現象は、部分的には、o.__proto__ 異常であるオブジェクトはのプロトタイプを持っている場合null

オブジェクト[[Prototype]]は、オブジェクトの作成時に最初に設定されます。

を介して新しいオブジェクトを作成する場合、デフォルトでは、new Func()オブジェクトの[[Prototype]]はによって参照されるオブジェクトに設定されますFunc.prototype

したがって、演算子で使用できるすべてのクラスとすべての関数には、独自の内部スロットに加えてnew名前が付けられたプロパティがある.prototype[[Prototype]]ことに注意してくださいこの「プロトタイプ」という単語の二重使用は、その言語の初心者の間で際限のない混乱の原因となっています。

newコンストラクター関数で使用すると、JavaScriptで従来の継承をシミュレートできます。JavaScriptの継承システムは-これまで見てきたように-プロトタイプであり、クラスベースではありません。

JavaScriptにクラス構文が導入される前は、コンストラクター関数がクラスをシミュレートする唯一の方法でした。コンストラクター関数の.prototypeプロパティによって参照されるオブジェクトのプロパティは、共有メンバーと考えることができます。すなわち。各インスタンスで同じメンバー。クラスベースのシステムでは、メソッドはインスタンスごとに同じ方法で実装されるため、メソッドは概念的に.prototypeプロパティに追加されます。ただし、オブジェクトのフィールドはインスタンス固有であるため、構築中にオブジェクト自体に追加されます。

クラス構文がない場合、開発者はプロトタイプチェーンを手動で構成して、従来の継承と同様の機能を実現する必要がありました。これにより、これを達成するためのさまざまな方法が圧倒的に多くなりました。

これが1つの方法です。

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
  child.prototype = Object.create(parent.prototype)
  child.prototype.constructor = child
  return child;
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

...そしてここに別の方法があります:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
    function tmp() {}
    tmp.prototype = parent.prototype
    const proto = new tmp()
    proto.constructor = child
    child.prototype = proto
    return child
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

ES2015で導入されたクラス構文extendsは、JavaScriptの従来の継承をシミュレートするためにプロトタイプチェーンを構成する「真の方法」として提供することで、物事を簡素化します。

したがって、上記のコードと同様に、クラス構文を使用して次のように新しいオブジェクトを作成するとします。

class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}

const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

...結果のオブジェクトの[[Prototype]]インスタンスに設定されますParentその、[[Prototype]]、順番に、ですParent.prototype

最後に、を介して新しいオブジェクトを作成するObject.create(foo)と、結果のオブジェクト[[Prototype]]はに設定されfooます。


1
だから、私は私の短いスニペットのプロトタイププロパティに新しいプロパティを定義することによって何か間違っているのですか?
ジョンライデグレン、2009

3
これが、一流の市民として機能オブジェクトを持つことの意味だと思います。
John Leidegren、2009

8
特にプログラミング言語では、標準的でないものが嫌いですが、明らかに不要なプロトさえあるのはなぜですか?
ジョンライデグレン、2009

1
@John __proto__は、JSインタープリターによる内部使用のみに必要です。各オブジェクトは、どのプロパティとメソッドがプロトタイプの一部であり、どれがオブジェクト自体の一部であるかを知る必要があります。JSインタープリターは、オブジェクトでプロトタイプ化されたメソッドを呼び出すことができる必要があります。
BMiner

17
[[Prototype]]の使用は意図的なものであることに注意してください-ECMA-262は内部プロパティの名前を二重角括弧で囲みます
Christoph

1798

Java、C#、C ++のような従来の継承を実装する言語では、まずクラス(オブジェクトの青写真)を作成し、そのクラスから新しいオブジェクトを作成するか、クラスを拡張して、拡張する新しいクラスを定義します。元のクラス。

JavaScriptでは、最初にオブジェクトを作成し(クラスの概念はありません)、次に独自のオブジェクトを拡張したり、そこから新しいオブジェクトを作成したりできます。それは難しいことではありませんが、少し異質で、古典的な方法に慣れている人にとって代謝が難しいです。

例:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

これまではベースオブジェクトを拡張してきましたが、今度は別のオブジェクトを作成してからPersonから継承します。

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

前述のとおり、PersonでsetAmountDue()、getAmountDue()を呼び出すことはできません。

//The following statement generates an error.
john.setAmountDue(1000);

352
stackoverflowの回答は、元のポスターだけでなく、検索に潜んでいる、または検索から来ている他の人々の大きなコミュニティにとっても興味深いと思います。そして、私はそれらの1人であり、古い投稿から利益を得ました。私はいくつかのコード例を追加して他の答えに貢献できると思います。あなたの質問について:あなたが新しいものを省くと、それはうまくいきません。myCustomer.sayMyName()を呼び出すと、「myCustomer.sayMyNameは関数ではありません」が返されます。最も簡単な方法は、Firebugを実験して何が起こるかを確認することです。
stivlo 2011年

7
私が理解している限り、var Person = function(name){...}; Personオブジェクトを構築できるコンストラクター関数を定義しています。したがって、まだObjectはなく、匿名コンストラクター関数だけがPersonに割り当てられています。これは非常に良い説明です: helephant.com/2008/08/how-javascript-objects-work
stivlo

17
警告:この回答は、親クラスのコンストラクターがインスタンスごとに呼び出されないという事実を無視しています。それが機能する唯一の理由は、彼が子と親のコンストラクターの両方でまったく同じことをした(名前を設定した)ためです。JavaScriptで継承を試行する際に発生する一般的な間違いの詳細な説明(および最終的な解決策)については、次を参照してください: このスタックオーバーフローの投稿
Aaren Cordova

3
この回答でも、「new Person()」をプロトタイプとして使用することで、「Person」の「name」インスタンスプロパティを「Customer」の静的プロパティに設定している(つまり、すべてのCustomerインスタンスは同じプロパティを持ちます)。これは良い基本的な例ですが、しないでください。:)プロトタイプを「Person.prototype」に設定して「ブリッジ」として機能する新しい匿名関数を作成し、それからインスタンスを作成して、代わりに「Customer.prototype」をその匿名インスタンスに設定します。
James Wilkins、

10
このCustomer.prototype = new Person();行について、MDNはを使用した例を示し、「ここでの一般的なエラーは「new Person()を使用することです」」Customer.prototype = Object.create(Person.prototype)と述べています出典
Rafael Eyng

186

これは非常に単純なプロトタイプベースのオブジェクトモデルであり、説明中にサンプルと見なされますが、まだコメントはありません。

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

プロトタイプの概念を検討する前に、考慮すべき重要な点がいくつかあります。

1- JavaScript関数が実際に機能する方法:

最初のステップを実行するには、JavaScript関数が実際にどのように機能するか、thisキーワードを使用するクラスのような関数として、または引数を持つ通常の関数として、何をして何を返すかを理解する必要があります。

Personオブジェクトモデルを作成するとします。しかし、このステップではキーワードを使用せずに、まったく同じことprototypenew実行しようとしてます。

したがって、このステップfunctionsではobjectsthisキーワードがすべて揃っています。

最初の質問は次のようになりますどのようにthisキーワードを使用することなく、有用である可能性newのキーワードを

そのため、空のオブジェクトと次のような2つの関数があるとします。

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

function getName(){
    console.log(this.name);
}

そして今、使用しなくてもnewキーワードを、私たちは、これらの機能を使用することができますか。したがって、JavaScriptには次の3つの方法があります。

a。最初の方法は、関数を通常の関数として呼び出すことです。

Person("George");
getName();//would print the "George" in the console

この場合には、これは、通常、グローバルで現在のコンテキストオブジェクト、あろう windowブラウザまたはオブジェクトGLOBALNode.js。これは、ブラウザのwindow.nameまたはNode.jsのGLOBAL.nameに "George"を値として持つことを意味します。

b。プロパティとしてそれらをオブジェクトにアタッチできます

- これを行う最も簡単な方法person、次のように空のオブジェクトを変更することです。

person.Person = Person;
person.getName = getName;

このようにして、次のように呼び出すことができます。

person.Person("George");
person.getName();// -->"George"

そして今、personオブジェクトは次のようなものです:

Object {Person: function, getName: function, name: "George"}

- オブジェクトにプロパティをアタッチするもう1つの方法prototype、名前がのJavaScriptオブジェクトで見つかるそのオブジェクトのを使用__proto__することです。概要の部分で少し説明しようとしました。したがって、次のようにすることで同様の結果を得ることができます。

person.__proto__.Person = Person;
person.__proto__.getName = getName;

しかし、この方法で実際に行っているのはを変更することです。Object.prototypeリテラル({ ... })を使用してJavaScriptオブジェクトを作成するときは常に、に基づいてObject.prototype作成されます。つまり、新しく作成されたオブジェクトにという属性としてアタッチされる__proto__ため、 、以前のコードスニペットで行ったように、すべてのJavaScriptオブジェクトが変更されるため、お勧めできません。それで、今より良い方法は何ですか?

person.__proto__ = {
    Person: Person,
    getName: getName
};

そして今、他のオブジェクトは平和ですが、それでもまだ良い習慣ではないようです。したがって、さらに1つのソリューションがありますが、このソリューションを使用するには、personオブジェクトが作成されたコード行に戻り(var person = {};)、次のように変更する必要があります。

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

それが行うことは、新しいJavaScript Objectを作成propertiesObjectし、__proto__属性にをアタッチすることです。だからあなたができることを確認するために:

console.log(person.__proto__===propertiesObject); //true

ただし、ここで注意が必要__proto__なのは、personオブジェクトの第1レベルで定義されているすべてのプロパティにアクセスできることです(詳細については、概要部分を参照してください)。


ご覧のthisとおり、これらの2つの方法のいずれかを使用すると、personオブジェクトが正確に示されます。

c。JavaScriptには、関数this呼び出すための別の方法があり、callまたはapplyを使用して関数を呼び出します。

apply()メソッドは、指定されたthis値と配列(または配列のようなオブジェクト)として提供された引数を使用して関数を呼び出します。

そして

call()メソッドは、指定されたthis値と個別に提供された引数を使用して関数を呼び出します。

この方法が私のお気に入りです。次のような関数を簡単に呼び出すことができます。

Person.call(person, "George");

または

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

これら3つの方法は、.prototype機能を理解するための重要な最初のステップです。


2- newキーワードはどのように機能しますか?

これは、.prototype機能を理解するための2番目のステップです。これは、プロセスをシミュレートするために使用するものです。

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

この部分では、newキーワードprototypeを使用するときに、キーワードand を使用せずに、JavaScriptが実行するすべての手順を実行しようとしていますnew。そのためnew Person("George")Person関数はコンストラクタとして機能します。JavaScriptが実行する処理は次のとおりです。

a。まず、空のオブジェクト、基本的には次のような空のハッシュを作成します。

var newObject = {};

b。JavaScriptが実行する次のステップは、すべてのプロトタイプオブジェクトを新しく作成されたオブジェクトにアタッチすることです

我々はmy_person_prototypeここではプロトタイプオブジェクトに似ています。

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

JavaScriptがプロトタイプで定義されているプロパティを実際にアタッチする方法ではありません。実際の方法は、プロトタイプチェーンのコンセプトに関連しています。


a。&b。これらの2つのステップの代わりに、次のようにすることでまったく同じ結果を得ることができます。

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

これで、次のgetName関数を呼び出すことができますmy_person_prototype

newObject.getName();

c。次に、そのオブジェクトをコンストラクターに渡します。

次のようなサンプルでこれを行うことができます。

Person.call(newObject, "George");

または

Person.apply(newObject, ["George"]);

このコンストラクターの内部は、作成されたばかりのオブジェクトであるため、コンストラクターは何でも実行できます。

他のステップをシミュレートする前の最終結果:Object {name: "George"}


概要:

基本的に、関数で新しいキーワードを使用すると、そのキーワードが呼び出され、その関数はコンストラクターとして機能するため、次のように言います。

new FunctionName()

JavaScriptは、内部オブジェクト、空のハッシュを作り、ので、それは、その後、コンストラクタはそれを望んでいるものは何でもすることができ、コンストラクタにそのオブジェクトを提供します。このようコンストラクタの内部だけで作成されたオブジェクトであり、それはあなたのコースのそのオブジェクトを提供します関数でreturnステートメントを使用していない場合、またはreturn undefined;関数本体の最後にを配置した場合。

そのため、JavaScriptがオブジェクトのプロパティを検索する場合、JavaScriptが最初に行うのは、そのオブジェクトのプロパティを検索することです。そして、[[prototype]]私たちが通常持っているような秘密のプロパティがあり__proto__、そのプロパティはJavaScriptが次に見るものです。そして、それ__proto__が再び別のJavaScriptオブジェクトである限り、それ自身の__proto__属性を持ち、次__proto__をnull となるポイントに到達するまで、上から上に移動します。ポイントは、その__proto__属性がnull であるJavaScriptの唯一のオブジェクトはObject.prototypeオブジェクトです。

console.log(Object.prototype.__proto__===null);//true

これがJavaScriptで継承が機能する方法です。

プロトタイプチェーン

言い換えると、関数にプロトタイププロパティがあり、その上で新しいプロパティを呼び出すと、JavaScriptが新しく作成されたプロパティのオブジェクトの確認を終えた後、関数のプロパティが確認され、.prototypeこのオブジェクトに独自の内部プロトタイプ。等々。


6
a)の内部を設定する)性質bをコピーしてプロトタイプを説明しないでください[[プロトタイプ]]コンストラクタ関数はインスタンスに適用される前に、jQueryのは、この問題の完全offtopicである)の順cを変更してください起こる
Bergi

1
@Bergi:指摘してくれてありがとう。それでいいかどうか教えていただければ幸いです。
Mehran Hatami

7
簡単にしていただけませんか?あなたはすべての点で正しいですが、この説明を読んだ学生は初めて本当に混乱するかもしれません。より簡単な例を選び、コードにそれ自体を説明させるか、意味を明確にするために一連のコメントを追加します。
午後

2
@PM:ご意見ありがとうございます。できるだけシンプルにするように心がけましたが、まだ曖昧な点があります。だから私はそれを修正して、もっと説明的になるようにします。:)
Mehran Hatami 14

1
@AndreaMattioliは、この方法で完全に新しいオブジェクトを作成し、他のオブジェクト間でも共有されている可能性のある古いオブジェクトを上書きするためです。置き換える__proto__ことにより、最初にすべてのトップレベルのプロトタイププロパティを一掃し、次に、共有しない限り共有されない新しいプロトベースを取得します。
Mehran Hatami

77

プロトタイプの7つの公案

深い瞑想の後、チロサンがマウントファイアフォックスを降りたとき、彼の心は明確で平和でした。

しかし、彼の手は落ち着きがなく、それ自体が筆をつかんで次のメモを書き留めました。


0) 2つの異なるものを「プロトタイプ」と呼ぶことができます。

  • プロトタイププロパティ obj.prototype

  • [[Prototype]] ES5のよう表示されるプロトタイプ内部プロパティ。

    ES5から取得できますObject.getPrototypeOf()

    Firefoxでは__proto__、拡張機能としてプロパティを介してアクセスできます。ES6は、のいくつかのオプション要件に言及しています__proto__


1)これらの概念は、質問に答えるために存在します。

私が行うときobj.property、JSはどこを探します.propertyか?

直感的に、古典的な継承はプロパティのルックアップに影響を与えるはずです。


2)

  • __proto__のように、ドット.プロパティのルックアップに使用されobj.propertyます。
  • .prototypeを使用したオブジェクトの作成時に決定されるため、間接的にのみ使用され、直接のルックアップに使用されません__proto__new

検索順序は次のとおりです。

  • objobj.p = ...またはで追加されたプロパティObject.defineProperty(obj, ...)
  • の特性 obj.__proto__
  • 性質obj.__proto__.__proto__、および上そう
  • ある場合__proto__null戻りundefinedます。

これは、いわゆるプロトタイプチェーンです。

との.ルックアップを回避できますobj.hasOwnProperty('key')Object.getOwnPropertyNames(f)


3)設定には主に2つの方法がありますobj.__proto__

  • new

    var F = function() {}
    var f = new F()

    次にnew設定しました:

    f.__proto__ === F.prototype

    これ.prototype慣れるところです。

  • Object.create

     f = Object.create(proto)

    セット:

    f.__proto__ === proto

4)コード:

var F = function(i) { this.i = i }
var f = new F(1)

次の図に対応します(一部Numberは省略されています)。

(Function)       (  F  )                                      (f)----->(1)
 |  ^             | | ^                                        |   i    |
 |  |             | | |                                        |        |
 |  |             | | +-------------------------+              |        |
 |  |constructor  | |                           |              |        |
 |  |             | +--------------+            |              |        |
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |  |             |                | +----------+              |        |
 |  |             |                | |                         |        |
 |  |             |                | | +-----------------------+        |
 |  |             |                | | |                                |
 v  |             v                v | v                                |
(Function.prototype)              (F.prototype)                         |
 |                                 |                                    |
 |                                 |                                    |
 |[[Prototype]]                    |[[Prototype]]          [[Prototype]]|
 |                                 |                                    |
 |                                 |                                    |
 | +-------------------------------+                                    |
 | |                                                                    |
 v v                                                                    v
(Object.prototype)                                       (Number.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

この図は、多くの言語の定義済みオブジェクトノードを示しています。

  • null
  • Object
  • Object.prototype
  • Function
  • Function.prototype
  • 1
  • Number.prototype(で見つけることができ(1).__proto__、構文を満たすには括弧が必須です)

2行のコードでは、次の新しいオブジェクトのみが作成されました。

  • f
  • F
  • F.prototype

iのプロパティになりましfた。

var f = new F(1)

それが評価されFthis値でnew、その後に割り当てられます戻りますが、f


5) .constructor通常から来F.prototype.、ルックアップ:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

を記述するとf.constructor、JavaScriptは次のように.検索を行います。

  • f 持っていない .constructor
  • f.__proto__ === F.prototype持っている.constructor === Fので、それを取る

従来のOOP言語と同じように、フィールドの設定などに使用されるf.constructor == Fため、結果は直感的に正確です。Ff


6)古典的な継承構文は、プロトタイプチェーンを操作することで実現できます。

ES6ではclassand extendsキーワードが追加されています。これらは主に、以前は可能だったプロトタイプ操作の狂気の構文糖です。

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
c = new C(1)
c.inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

事前定義されたオブジェクトをすべて含まない簡略図:

(c)----->(1)
 |   i
 |
 |
 |[[Prototype]]
 |
 |
 v    __proto__
(C)<--------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |[[Prototype]] 
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|[[Prototype]]    (D.prototype)--------> (inc2 function object)
| |                |             inc2
| |                |
| |                |[[Prototype]]
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)------->(inc function object)
|                inc
v
Function.prototype

少し時間をとって、以下がどのように機能するかを調べてみましょう:

c = new C(1)
c.inc() === 2

最初の行は、「4)」で説明したように設定c.i1れます。

2行目では、次のことを行います。

c.inc()
  • .inc[[Prototype]]チェーンを通して見つかります:c-> C-> C.prototype->inc
  • X.Y()JavaScriptで関数をとして呼び出すと、JavaScript は関数呼び出し内で自動的thisに等しいと設定します。XY()

まったく同じロジックで、とも説明されd.incていd.inc2ます。

この記事https://javascript.info/class#not-just-a-syntax-sugarは、class知っておく価値のあるさらなる影響について述べています。それらのいくつかは、classキーワードなしでは達成できない場合があります(TODOで確認してください)。


1
@tomasbありがとう!「どこでこれを得たのかわかりません」:これらの動的言語をいくつか見た後、クラスシステムで最も重要なのは.ルックアップのしくみ(およびデータのコピーがいくつ作成されるか)であることに気付きました。。それで私はその点を理解しようと試みました。残りはGoogle +ブログ投稿+ Jsインタープリターです。:)
Ciro Santilli冠状病毒审查六四事件法轮功

1
「4)f = new Fを実行すると、newはf.constructor = Fも設定する」と言ったので、なぜg.constructor === Objectなのかはわかりません。もっと説明してもらえますか?とにかくこれが私が探している最良の答えです。どうもありがとうございます!
nguyenngoc101 2015

@ nguyenngoc101ありがとう!そのsets f.constructor = F部分は露骨に間違っていて、以降のセクションと矛盾し.constructorてい.ます。プロトタイプチェーンを検索すると見つかります。今それを修正しました。
Ciro Santilli冠状病毒审查六四事件法轮功

コンストラクター関数を作成し、新しい演算子を使用してそのインスタンスを作成しようとした場合、すべての議論から何が得られるか(従来の継承から来た)プロトオブジェクトにアタッチされたメソッドとプロパティのみを取得するため、すべてのメソッドをアタッチする必要がある継承したい場合は、プロトオブジェクトにプロパティを設定しますか?
blackHawk 2016年

1
@CiroSantilli刘晓波死六四事件法轮功これはChromiumのバグではないと思います。fプロトタイプがF構築時にのみ設定されるのは単なる症状だと思います。それが最初に構築された後は、いつでもf知りませんし、気にしませんF.prototype
John Glassmyer 2017

76

prototypeクラスを作ることができます。使用しない場合prototypeは静的になります。

これは短い例です。

var obj = new Object();
obj.test = function() { alert('Hello?'); };

上記の場合、静的関数呼び出しテストがあります。この関数は、objがクラスであると想像できるobj.testによってのみアクセスできます。

以下のコードのように

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

objは、インスタンス化できるクラスになりました。objの複数のインスタンスが存在する可能性があり、それらすべてにtest機能があります。

上記は私の理解です。私はそれをコミュニティーwikiにしているので、私が間違っている場合、人々は私を訂正することができます。


13
-1:prototypeはインスタンスではなくコンストラクタ関数のプロパティです。つまり、コードが間違っています!おそらく__proto__、オブジェクトの非標準的なプロパティを意味していたかもしれませんが、それはまったく別の獣です...
クリストフ

@Christoph-指摘してくれてありがとう。サンプルコードを更新しました。
Ramesh、

3
それだけではありません...さらに、JavaScriptはクラスベースの言語ではありません-プロトタイプを介した継承を扱うため、違いをより詳しくカバーする必要があります!
ジェームズ

5
この答えは少し誤解を招くと思います。
Armin Cifuentes 2013

多分答えは「誤解」ですが、プロトタイプが何に使用されているのかを説明し、今では何百もの「賛成」票での「答え」の後に、私にはすべて明らかです。ありがとうございました。
Aleks、2015年

66

このスレッドを読んだ後、JavaScriptプロトタイプチェーンに戸惑い、これらのチャートを見つけました

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance 関数オブジェクトの* [[protytype]] *および<code> prototype </ code>プロパティ

プロトタイプチェーンによるJavaScript継承を示す明確なチャートです

そして

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

これには、コードといくつかの素晴らしい図の例が含まれています。

プロトタイプチェーンは最終的にObject.prototypeにフォールバックします。

プロトタイプチェーンは、サブクラスのプロトタイプを親クラスのオブジェクトと等しく設定することにより、いつでも技術的に拡張できます。

JavaScriptプロトタイプチェーンを理解することも役立つと思います。


Javascriptに複数の継承を持たせることは可能ですか?

ここでFooはオブジェクトリテラルですか、それとも関数オブジェクトですか?オブジェクトリテラルの場合、Foo.prototypeはコンストラクタを介してFooをポイントしないと思います。
Madhur Ahuja 14

@ user3376708 JavaScriptは単一継承のみをサポートソース
Rafael Eyng

@ Nuno_147最初ははっきりしていませんが、十分に長く見ていると、何かが得られる可能性があります。
marcelocra 2014

3
どういう[[Prototype]]意味ですか?
CodyBugstein 2014年

40

すべてのオブジェクトには内部プロパティ[[Prototype]]があり、別のオブジェクトにリンクしています。

object [[Prototype]]  anotherObject

従来のjavascriptでは、リンクされたオブジェクトはprototype関数のプロパティです:

object [[Prototype]]  aFunction.prototype

一部の環境では、[[Prototype]]__proto__次のように公開されます。

anObject.__proto__ === anotherObject

あなたは、作成[[プロトタイプ]]オブジェクトを作成するときにリンクを。

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

したがって、これらのステートメントは同等です。

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

新しいステートメントObject.prototypeでは実際にはリンクターゲット()を確認できません。代わりに、ターゲットはコンストラクター()によって暗黙指定されます。Object

覚えておいてください:

  • すべてのオブジェクトにはリンク[[Prototype]]があり、__proto__として公開される場合があります。
  • すべての関数にはprototypeプロパティがあり、最初は空のオブジェクトを保持しています。
  • newで作成されたオブジェクトprototypeは、コンストラクターのプロパティにリンクされます。
  • 関数がコンストラクターとして使用されない場合、そのprototypeプロパティは使用されません。
  • コンストラクタが必要ない場合は、の代わりにObject.createを使用してくださいnew

1
リビジョン5では、Object.create()に関する情報を含むいくつかの有用な情報が削除されました。リビジョン4を参照してください。
Palec、2015

@Palec何を追加すればよいですか?
sam 2015

2
IMO少なくともObject.create()docsへのリンク、@ sam。へのリンク__proto__Object.prototypeは、素晴らしい拡張機能です。そして、プロトタイプがコンストラクターやでどのように機能するかの例が好きでしたが、Object.create()おそらくそれらは、あなたが取り除く必要があった長くて関連性の低い部分でした。
Palec、2015

コンストラクター関数を作成し、新しい演算子を使用してそのインスタンスを作成しようとした場合、すべての議論から何が得られるか(従来の継承から来た)プロトオブジェクトにアタッチされたメソッドとプロパティのみを取得するため、すべてのメソッドをアタッチする必要がある継承したい場合は、プロトオブジェクトにプロパティを設定しますか?
blackHawk 2016年

29

Javascriptには通常の意味での継承はありませんが、プロトタイプチェーンがあります。

プロトタイプチェーン

オブジェクトのメンバーがオブジェクト内に見つからない場合は、プロトタイプチェーンでそれを探します。チェーンは他のオブジェクトで構成されています。特定のインスタンスのプロトタイプには、__proto__変数を使用してアクセスできます。JavaScriptではクラスとインスタンスに違いがないため、すべてのオブジェクトに1つあります。

関数/変数をプロトタイプに追加する利点は、すべてのインスタンスに対してではなく、一度だけメモリにある必要があることです。

プロトタイプチェーンは他の多くのオブジェクトで構成できるため、継承にも役立ちます。


1
FFとChromeはprotoをサポートしていますが、IEやOperaはサポートしていません。
いくつかの

Georg、noobを明確にしてください-「javascriptのクラスとインスタンスに違いはありません。」-詳しく説明してもらえますか?これはどのように作動しますか?
Hamish Grubijan、2012年

コンストラクター関数を作成し、新しい演算子を使用してそのインスタンスを作成しようとした場合、すべての議論から何が得られるか(従来の継承から来た)プロトオブジェクトにアタッチされたメソッドとプロパティのみを取得するため、すべてのメソッドをアタッチする必要がある継承したい場合は、プロトオブジェクトにプロパティを設定しますか?
blackHawk 2016年

28

この記事は長いです。しかし、JavaScript継承の「典型的な」性質に関するほとんどのクエリはクリアされると思います。そしてさらに。完全な記事を読んでください。

JavaScriptには基本的に2種類のデータ型があります

  • 非オブジェクト
  • オブジェクト

非オブジェクト

以下は、非オブジェクトデータ型です。

  • ストリング
  • 数(NaNと無限大を含む)
  • ブール値(true、false)
  • 未定義

typeof演算子を使用すると、これらのデータ型は以下を返します

typeof "文字列リテラル"(または文字列リテラルを含む変数)=== 'string'

typeof 5(または任意の数値リテラルまたは数値リテラルまたはNaNまたはInfynityを含む変数)=== 'number'

typeof true(またはfalseまたはtrueまたはfalseを含む変数)=== 'boolean'

typeof undefined(またはundefined変数またはundefinedを含む変数)=== 'undefined'

文字列番号およびブールデータ型は両方として表すことができるオブジェクトおよび非オブジェクト彼らは彼らのtypeof演算は常に===「オブジェクト」ですオブジェクトとして表現されている.Whenを。オブジェクトのデータ型を理解したら、これに戻ります。

オブジェクト

オブジェクトのデータ型は、さらに2つのタイプに分類できます。

  1. 関数型オブジェクト
  2. 非関数型オブジェクト

関数型オブジェクトは、文字列を返すものです「機能」付きのtypeof演算子を。すべてのユーザー定義関数と、new演算子を使用して新しいオブジェクトを作成できるすべてのJavaScript組み込みオブジェクトは、このカテゴリに分類されます。たとえば

  • オブジェクト
  • ストリング
  • ブール
  • アレイ
  • 型付き配列
  • RegExp
  • 関数
  • new演算子を使用して新しいオブジェクトを作成できるその他すべての組み込みオブジェクト
  • function UserDefinedFunction(){/ *ユーザー定義コード* /}

したがって、 typeof(Object) === typeof(String) === typeof(Number) === typeof(Boolean) === typeof(Array) === typeof(RegExp) === typeof(Function) == = typeof(UserDefinedFunction) === '関数'

すべてのFunctionタイプオブジェクトは、実際には組み込みのJavaScriptオブジェクトFunctionFunctionオブジェクトを含む、つまり再帰的に定義される)のインスタンスです。これらのオブジェクトが次のように定義されているかのようです。

var Object= new Function ([native code for object Object])
var String= new Function ([native code for object String])
var Number= new Function ([native code for object Number])
var Boolean= new Function ([native code for object Boolean])
var Array= new Function ([native code for object Array])
var RegExp= new Function ([native code for object RegExp])
var Function= new Function ([native code  for object Function])
var UserDefinedFunction= new Function ("user defined code")

前述のように、Functionタイプのオブジェクトは、new演算子を使用して新しいオブジェクトをさらに作成できます。たとえば、タイプObjectStringNumberBooleanArrayRegExp またはUserDefinedFunctionのオブジェクトは、以下を使用して作成できます。

var a=new Object() or var a=Object() or var a={} //Create object of type Object
var a=new String() //Create object of type String
var a=new Number() //Create object of type Number
var a=new Boolean() //Create object of type Boolean
var a=new Array() or var a=Array() or var a=[]  //Create object of type Array
var a=new RegExp() or var a=RegExp() //Create object of type RegExp
var a=new UserDefinedFunction() 

このようにして作成されたオブジェクトはすべて非関数タイプのオブジェクトであり、そのtypeof === 'object'を返します。これらすべての場合において、オブジェクト "a"は、演算子newを使用してオブジェクトをさらに作成することはできません。したがって、以下は間違っています

var b=new a() //error. a is not typeof==='function'

組み込みオブジェクトMathtypeof === 'object'です。したがって、Mathタイプの新しいオブジェクトをnew演算子で作成することはできません。

var b=new Math() //error. Math is not typeof==='function'

また、ObjectArrayRegExp関数は、operator newを使用しなくても新しいオブジェクトを作成できることに注意してください。しかし、次のものはしません。

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

ユーザー定義関数は特殊なケースです。

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

以来関数型のオブジェクトが新しいオブジェクトを作成することができ、それらも呼ばれているコンストラクタ

すべてのコンストラクター/関数(組み込みでもユーザー定義でも)を定義すると、自動的に「プロトタイプ」と呼ばれるプロパティがあり、その値はデフォルトでオブジェクトとして設定されます。このオブジェクト自体には、「コンストラクタ」と呼ばれるプロパティがあり、デフォルトではコンストラクタ/関数を参照します。

たとえば関数を定義するとき

function UserDefinedFunction()
{
}

以下が自動的に起こります

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

この「プロトタイプ」プロパティは、関数型オブジェクトにのみ存在します非関数型オブジェクトには存在しません)。

これは、新しいオブジェクトが(新しい演算子を使用して)作成されると、コンストラクター関数の現在のプロトタイプオブジェクトからすべてのプロパティとメソッドを継承するためです。つまり、 コンストラクター関数の現在のプロトタイプオブジェクトによって参照されるオブジェクトを参照する、新しく作成されたオブジェクトに内部参照 が作成されます。

継承されたプロパティを参照するためにオブジェクト内に作成されるこの「内部参照」は、オブジェクトのプロトタイプと呼ばれます(コンストラクタの「プロトタイプ」プロパティによって参照されるオブジェクトを参照しますが、オブジェクトとは異なります)。任意のオブジェクト(関数または非関数)の場合、これはObject.getPrototypeOf()メソッドを使用して取得できます。この方法を使用すると、オブジェクトのプロトタイプチェーンをトレースできます。

また、作成されるすべてのオブジェクト関数型または非関数型)には、コンストラクター関数のプロトタイププロパティによって参照されるオブジェクトから継承される「コンストラクター」プロパティがあります。デフォルトでは、この「コンストラクター」プロパティーは、それを作成したコンストラクター関数を参照しますコンストラクター関数のデフォルトの「プロトタイプ」が変更されていない場合)。

すべての関数型オブジェクトの場合、コンストラクター関数は常に 関数Function(){}です

以下のために非機能型オブジェクト(例えばJavascriptがMathオブジェクトに内蔵)コンストラクタ関数は、それを作成した機能です。ための数学オブジェクトそれは関数オブジェクト(){}

上記で説明したすべての概念は、サポートコードなしでは理解するのが少し難しいかもしれません。概念を理解するには、次のコードを1行ずつ実行してください。理解を深めるために実行してみてください。

function UserDefinedFunction()
{ 

} 

/* creating the above function automatically does the following as mentioned earlier

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

*/


var newObj_1=new UserDefinedFunction()

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays true

alert(newObj_1.constructor) //Displays function UserDefinedFunction

//Create a new property in UserDefinedFunction.prototype object

UserDefinedFunction.prototype.TestProperty="test"

alert(newObj_1.TestProperty) //Displays "test"

alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"

//Create a new Object

var objA = {
        property1 : "Property1",
        constructor:Array

}


//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays false. The object referenced by UserDefinedFunction.prototype has changed

//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction

alert(newObj_1.TestProperty) //This shall still Display "test" 

alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"


//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();

alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.

alert(newObj_2.constructor) //Displays function Array()

alert(newObj_2.property1) //Displays "Property1"

alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"

//Create a new property in objA
objA.property2="property2"

alert(objA.property2) //Displays "Property2"

alert(UserDefinedFunction.prototype.property2) //Displays "Property2"

alert(newObj_2.property2) // Displays Property2

alert(Object.getPrototypeOf(newObj_2).property2) //Displays  "Property2"

すべてのオブジェクトのプロトタイプチェーンは、最終的にObject.prototype(プロトタイプオブジェクトを持たない)までさかのぼります。次のコードは、オブジェクトのプロトタイプチェーンをトレースするために使用できます。

var o=Starting object;

do {
    alert(o + "\n" + Object.getOwnPropertyNames(o))

}while(o=Object.getPrototypeOf(o))

さまざまなオブジェクトのプロトタイプチェーンは次のように機能します。

  • すべてのFunctionオブジェクト(組み込みのFunctionオブジェクトを含む)-> Function.prototype-> Object.prototype-> null
  • 単純なオブジェクト(new Math()または{}によって作成され、組み込みのMathオブジェクトを含む)-> Object.prototype-> null
  • newまたはObject.createで作成されたオブジェクト-> 1つ以上のプロトタイプチェーン-> Object.prototype-> null

プロトタイプなしでオブジェクトを作成するには、以下を使用します。

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null

コンストラクタのプロトタイププロパティをnullに設定すると、nullプロトタイプを持つオブジェクトが作成されると考えられるかもしれません。ただし、このような場合、新しく作成されたオブジェクトのプロトタイプはObject.prototypeに設定され、そのコンストラクターは関数Objectに設定されます。これは次のコードで示されています

function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)

var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype)   //Displays true
alert(o.constructor)    //Displays Function Object

この記事の要約に続く

  • オブジェクトには、関数タイプ非関数タイプの 2つのタイプがあります。
  • 演算子newを使用して新しいオブジェクトを作成できるのは、Functionタイプのオブジェクトのみです。このようにして作成されたオブジェクトは、非関数タイプのオブジェクトです。非機能型のオブジェクトは、さらに使用してオブジェクトを作成することはできませんnew演算子を

  • すべての関数型オブジェクトには、デフォルトで「プロトタイプ」プロパティがあります。この「プロトタイプ」プロパティは、デフォルトで関数タイプオブジェクト自体を参照する「コンストラクタ」プロパティを持つオブジェクトを参照します。

  • すべてのオブジェクト(関数タイプおよび非関数タイプ)には、デフォルトで、それを作成した関数タイプオブジェクト / コンストラクターを参照する「コンストラクター」プロパティがあります。

  • 内部で作成されるすべてのオブジェクトは、それを作成したコンストラクターの「プロトタイプ」プロパティによって参照されるオブジェクトを参照します 。このオブジェクトは、作成されたオブジェクトのプロトタイプと呼ばれます(これは、参照する関数型オブジェクトの「プロトタイプ」プロパティとは異なります)。このようにして、作成されたオブジェクトは、コンストラクターの「プロトタイプ」プロパティによって参照されるオブジェクトで定義されたメソッドとプロパティに直接アクセスできます(オブジェクト作成時)。

  • オブジェクトのプロトタイプ(従って、その継承されたプロパティ名)を使用して取得することができるObject.getPrototypeOf() メソッドを。実際、このメソッドは、オブジェクトのプロトタイプチェーン全体をナビゲートするために使用できます。

  • すべてのオブジェクトのプロトタイプチェーンは、最終的にはObject.prototypeまでさかのぼります(オブジェクトがObject.create(null)を使用して作成されていない場合、オブジェクトにはプロトタイプがありません)。

  • typeof(new Array())=== 'object'は言語の設計によるものであり、Douglas Crockfordが指摘した誤りではありません

  • コンストラクターのプロトタイププロパティをnull(またはundefined、number、true、false、string)に設定しても、nullプロトタイプを持つオブジェクトは作成されません。そのような場合、新しく作成されたオブジェクトのプロトタイプはObject.prototypeに設定され、そのコンストラクターは関数Objectに設定されます。

お役に立てれば。


24

prototypal継承の概念は、多くの開発者にとって最も複雑な概念の1つです。問題の根本を理解して、理解を深めましょうprototypal inheritanceplain関数から始めましょう。

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

new演算子を使用する場合はTree functionconstructor関数として呼び出します。

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

すべてのJavaScript関数にはがありprototypeます。をログに記録するとTree.prototype、...

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

上記のconsole.log()出力を見ると、コンストラクターのプロパティTree.prototype__proto__プロパティも確認できます。__proto__表しprototype、これはことをfunctionオフに基づいて、これは単なるですので、されてJavaScript functionいないとinheritanceまだ設定、それが参照するObject prototypeだけではJavaScriptに組み込まれて何かあります...

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

これは.toString, .toValue, .hasOwnProperty等のようなものを持っています...

__proto__これは私のmozillaが非推奨Object.getPrototypeOfになり、を取得するメソッドに置き換えられましたobject's prototype

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

Object.getPrototypeOf(Tree.prototype); // Object {} 

メソッドをに追加してみましょうTree prototype

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

を変更しRootfunctionブランチを追加しました。

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

つまり、instanceof を作成するときに、そのメソッドをTree呼び出すことができますbranch

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

primitivesまたはobjectsをに追加することもできますPrototype

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

にを追加しchild-treeてみましょうTree

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

ここではTreeからChild継承していますが、ここでは、メソッドを使用して、渡したものに基づいて新しいオブジェクトを作成しています。この場合、Childのプロトタイプを、プロトタイプと同じに見える新しいオブジェクトに設定しています。次に、を設定します(設定しない場合はを指します)。prototypeObject.create()Tree.prototypeTreeChild's constructor to ChildTree()

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

Child今、自身の持っているprototype、その__proto__へのポイントTreeTree's prototypeベースにポイントをObject

Child  
|
 \
  \
   Tree.prototype
   - branch
   |
   |
    \
     \
      Object.prototype
      -toString
      -valueOf
      -etc., etc.

次に、最初にで利用できるinstanceof Childとcall branchを作成しTreeます。私たちは、実際に私たちを定義していませんbranchChild prototype。しかし、Root prototype子の継承元です。

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

JSでは、すべてがオブジェクトではなく、すべてがオブジェクトのように振る舞うことができます。

Javascriptstrings, number, booleans, undefined, null.彼らはのようなプリミティブを持っていますobject(i.e reference types)が、確かにのように行動することができobjectます。ここで例を見てみましょう。

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

このリストの最初の行では、primitive文字列値が名前に割り当てられています。2行目では、名前をanのように扱い、ドット表記を使用objectして呼び出しますcharAt(0)

これは舞台裏で起こります:// JavaScriptエンジンがすること

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

は、String object破棄される前の1つのステートメントにのみ存在します(プロセスと呼ばれるautoboxing)。再びに戻りましょうprototypal inheritance

  • Javascriptdelegation基づく継承をサポートし prototypesます。
  • それぞれに別のオブジェクトを参照Functionするprototypeプロパティがあります。
  • properties/functionsobjectそれ自体から、またはprototype存在しない場合はチェーンを介し て見られる

prototypeJSのA は、yields別のの親になるオブジェクトですobject[委任]と Delegationは、何かを実行できない場合、他の人に代わりに実行するように指示することを意味します。

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

https://jsfiddle.net/say0tzpL/1/

上記のフィドルを調べると、dogはtoStringメソッドにアクセスできますが、メソッドでは使用できませんが、以下にデリゲートするプロトタイプチェーンを介して使用できます。Object.prototype

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

以下のものを見ると、callすべてので利用可能なメソッドにアクセスしようとしていますfunction

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

https://jsfiddle.net/rknffckc/

上記のフィドルを調べると、ProfileFunctionはcallメソッドにアクセスできますが、メソッドでは使用できませんが、以下にデリゲートするプロトタイプチェーンを介して使用できます。Function.prototype

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

注: prototypeは関数コンストラクターのプロパティですが、関数コンストラク__proto__ターから作成されたオブジェクトのプロパティです。すべての関数にはprototype、値が空のプロパティが付属していますobject。関数のインスタンスを作成すると、内部プロパティが取得される[[Prototype]]__proto__、その参照がFunctionのプロトタイプになりconstructorます。

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

上の図は少し複雑に見えますが、動作の全体像を引き出しprototype chainingます。これについてゆっくりと見ていきましょう。

2つがあり、インスタンスがあるb1b2、そのコンストラクタでBar親のFooで、プロトタイプチェーンからの2つのメソッドを持っているidentifyspeak経由Barし、Foo

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

https://jsfiddle.net/kbp7jr7n/

上記のコードを調べるとFoo、メソッドを持つコンストラクタとメソッドを持つコンストラクタがあります。2つのインスタンスを作成し、その親タイプはです。これで、のメソッドを呼び出しているときに、誰がチェーンを介して話すかを特定できます。identify()BarspeakBarb1b2FoospeakBarprototype

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

BarにはFoo、そので定義されているすべてのメソッドがありますprototype。のは理解する上で、さらに掘り下げてみようObject.prototypeFunction.prototype、それらがどのように関連していますか。のコンストラクタを検索するとFooBarそしてObjectですFunction constructor

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

prototypeのがBarあるFooprototypeFooIS Objectとあなたが密接に見ればprototypeFooに関係していますObject.prototype

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

これを閉じる前に、ここで小さなコードでラップして、上記のすべて要約してみましょう。instanceofここで演算子を使用objectして、prototypeチェーンprototypeにa のプロパティがあるかどうかを確認してconstructorいます。

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

この追加がいくつかの情報になることを願っています。このことは把握するのが難しいかもしれません...簡単に言えば、オブジェクトにリンクされているオブジェクトだけです!!!!


22

この「.prototype」プロパティの正確な目的は何ですか?

標準クラスへのインターフェースは拡張可能になります。たとえば、Arrayクラスを使用していて、すべての配列オブジェクトにカスタムシリアライザーを追加する必要があるとします。サブクラスのコーディングに時間を費やしたり、コンポジションを使用したりしますか...プロトタイププロパティは、ユーザーがクラスで使用できるメンバー/メソッドの正確なセットを制御できるようにすることでこれを解決します。

プロトタイプを追加のvtable-pointerと考えてください。元のクラスに欠落しているメンバーがある場合、プロトタイプは実行時に検索されます。


21

プロトタイプチェーンを2つのカテゴリに分類すると役立つ場合があります。

コンストラクタを考えてみましょう:

 function Person() {}

の値Object.getPrototypeOf(Person)は関数です。実際、それはFunction.prototypeです。Personは関数として作成されたため、すべての関数が持つのと同じプロトタイプ関数オブジェクトを共有します。と同じですがPerson.__proto__、そのプロパティは使用しないでください。とにかく、Object.getPrototypeOf(Person)あなたはプロトタイプチェーンと呼ばれるもののはしごを効果的に歩きます。

上向きのチェーンは次のようになります。

    PersonFunction.prototypeObject.prototype(エンドポイント)

重要なのは、このプロトタイプチェーンは、構築Personできるオブジェクトとはほとんど関係がないということです。です。これらの構築されたオブジェクトには独自のプロトタイプチェーンがあり、このチェーンには、上記のものと共通する近い祖先がない可能性があります。

このオブジェクトを例にとります:

var p = new Person();

pPersonとの直接的なプロトタイプチェーン関係を持ちません。彼らの関係は別のものです。オブジェクトpには独自のプロトタイプチェーンがあります。を使用するObject.getPrototypeOfと、チェーンは次のようになります。

    pPerson.prototypeObject.prototype(エンドポイント)

このチェーンには関数オブジェクトがありません(それは可能です)。

だから、Person自分の生活を生き鎖の2つの種類に関連すると思われます。あるチェーンから別のチェーンに「ジャンプ」するには、次を使用します。

  1. .prototype:コンストラクタのチェーンから作成されたオブジェクトのチェーンにジャンプします。したがって、このプロパティは関数オブジェクトに対してのみ定義されます(関数でnewのみ使用できます)。

  2. .constructor:作成されたオブジェクトのチェーンからコンストラクタのチェーンにジャンプします。

以下は、列として表される、関連する2つのプロトタイプチェーンの視覚的表現です。

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

要約すると:

prototypeプロパティには何の情報の与えていない対象者が、オブジェクトの、プロトタイプチェーンをによって作成された対象。

プロパティの名前がprototype混乱を招く可能性があることは当然のことです。このプロパティに名前が付けられていたprototypeOfConstructedInstancesか、その行に沿って何かが付けられていた場合、それはおそらくより明確でした。

2つのプロトタイプチェーン間を行き来できます。

Person.prototype.constructor === Person

この対称性は、別のオブジェクトを明示的に prototypeプロパティにます(詳細は後で説明します)。

1つの関数を作成し、2つのオブジェクトを取得する

Person.prototype関数のPerson作成と同時に作成されたオブジェクトです。Personそのコンストラクタは実際にはまだ実行されていませんが、コンストラクタとして持っています。したがって、2つのオブジェクトが同時に作成されます。

  1. 関数Person自体
  2. 関数がコンストラクターとして呼び出されたときにプロトタイプとして機能するオブジェクト

どちらもオブジェクトですが、役割は異なります。関数オブジェクトはを構築し、もう一方のオブジェクトは関数が構築するオブジェクトのプロトタイプを表します。プロトタイプオブジェクトは、プロトタイプチェーンで構築されたオブジェクトの親になります。

関数はオブジェクトでもあるため、独自のプロトタイプチェーンにも独自の親がありますが、これら2つのチェーンは異なるものであることを思い出してください。

問題を把握するのに役立ついくつかの平等があります-これらすべての印刷物true

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

プロトタイプチェーンにレベルを追加する

コンストラクター関数を作成するとプロトタイプオブジェクトが作成されますが、そのオブジェクトを無視して、そのコンストラクターによって作成される後続のインスタンスのプロトタイプとして使用する必要がある別のオブジェクトを割り当てることができます。

例えば:

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

これで、tのプロトタイプチェーンは、pのプロトタイプチェーンよりも1ステップ長くなります。

    tpPerson.prototypeObject.prototype(エンドポイント)

他のプロトタイプチェーンは長くないですThiefし、Person彼らのプロトタイプチェーン内に同じ親を共有する兄弟であります:

    Person}
    Thief  }→ Function.prototypeObject.prototype(エンドポイント)

以前に表示されたグラフィックはこれに拡張できます(オリジナルThief.prototypeは省略されています)。

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

青い線はプロトタイプチェーンを表し、他の色付きの線は他の関係を表します。

  • オブジェクトとそのコンストラクタの間
  • コンストラクタとオブジェクトの構築に使用されるプロトタイプオブジェクトの間


16

obj_n.prop_X参照されている場合、「プロトタイプチェーン」を再帰的な慣習として説明すると便利です

obj_n.prop_X存在しない場合は、obj_n+1.prop_Xどこを確認してくださいobj_n+1 = obj_n.[[prototype]]

prop_X最終的にk番目のプロトタイプオブジェクトで見つかった場合

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

プロパティによるJavaScriptオブジェクトの関係のグラフは、次の場所にあります。

jsオブジェクトグラフ

http://jsobjects.org


14

コンストラクターがオブジェクトを作成すると、そのオブジェクトは、プロパティ参照を解決する目的で、コンストラクターの「プロトタイプ」プロパティを暗黙的に参照します。コンストラクターの「プロトタイプ」プロパティは、プログラム式のconstructor.prototypeによって参照でき、オブジェクトのプロトタイプに追加されたプロパティは、継承を通じて、プロトタイプを共有するすべてのオブジェクトによって共有されます。


11

説明が必要な、2つの異なるが関連するエンティティがあります。

  • .prototype関数のプロパティ。
  • すべてのオブジェクトの[[Prototype]][1]プロパティ[2]

これらは2つの異なるものです。

[[Prototype]]プロパティ:

これは、すべての[2]オブジェクトに存在するプロパティです。

ここに格納されているのは別のオブジェクトであり、オブジェクト自体として、[[Prototype]]別のオブジェクトを指す独自のオブジェクトを持っています。その他のオブジェクトには[[Prototype]]独自のがあります。このストーリーは、すべてのオブジェクト(など.toString)でアクセス可能なメソッドを提供する典型的なオブジェクトに到達するまで続きます。

[[Prototype]]プロパティは、形成するものの一部である[[Prototype]]チェーンを。このチェーン[[Prototype]]オブジェクトは、例えば、場合、検査されているものである[[Get]]か、[[Set]]操作がオブジェクトに実行されます。

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

.prototypeプロパティ:

これは、関数にのみ存在するプロパティです。非常に単純な関数を使用する:

function Bar(){};

.prototypeプロパティは、オブジェクトを保持に割り当てられますb.[[Prototype]]あなたが行うときにvar b = new Bar。これは簡単に調べることができます。

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

最も重要なの一つ.prototypesがあるということObject機能。このプロトタイプは、すべての[[Prototype]]チェーンに含まれる典型的なオブジェクトを保持します。その上で、新しいオブジェクトに使用できるすべてのメソッドが定義されています。

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

現在、.prototypeはオブジェクトなので、[[Prototype]]プロパティがあります。に割り当てを行わない場合Function.prototype.prototype[[Prototype]]ポイントはプロトタイプオブジェクト(Object.prototype)。これは、新しい関数を作成するたびに自動的に実行されます。

このようにしてnew Bar;、プロトタイプチェーンが設定されると、すべての定義Bar.prototypeとすべての定義が取得されObject.prototypeます。

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

あなたするFunction.prototypeすべてに割り当てを行うとき、あなたがしていることは、別のオブジェクトを含むようにプロトタイプチェーンを拡張することです。単一リンクリストへの挿入のようなものです。

これは基本的に[[Prototype]]チェーンを変更し、割り当てられたオブジェクトで定義されたプロパティがFunction.prototype、関数によって作成されたオブジェクトから見えるようにします。


[1:それは誰も混乱させません; プロパティを介し__proto__多くの実装で利用可能になります
[2]:を除くすべてnull


10

プロトタイプについての私の理解をお話ししましょう。ここでの継承を他の言語と比較するつもりはありません。言語の比較をやめて、言語そのものを理解してほしいと思います。以下に示すように、プロトタイプとプロトタイプの継承を理解するのはとても簡単です。

プロトタイプはモデルのようなもので、製品の作成に基づいています。理解しておくべき重要な点は、プロトタイプとして別のオブジェクトを使用してオブジェクトを作成する場合、プロトタイプと製品の間のリンクは永続するということです。例えば:

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

すべてのオブジェクトには、[[プロトタイプ]]と呼ばれる内部プロパティが含まれており、Object.getPrototypeOf()関数からアクセスできます。Object.create(model)新しいオブジェクトを作成し、その[[prototype]]プロパティをオブジェクトモデルに設定します。したがって、これを行うObject.getPrototypeOf(product)と、オブジェクトモデルが取得されます。

製品のプロパティは次のように処理されます。

  • プロパティにアクセスしてその値を読み取ると、スコープチェーンでルックアップされます。変数の検索は、製品からプロトタイプに向かって始まります。そのような変数が検索で見つかった場合、検索はそこですぐに停止され、値が返されます。そのような変数がスコープチェーンで見つからない場合、undefinedが返されます。
  • プロパティが書き込まれる(変更される)場合、プロパティは常に製品オブジェクトに書き込まれます。製品にそのようなプロパティがまだない場合は、暗黙的に作成および記述されます。

このようなprototypeプロパティを使用したオブジェクトのリンクは、プロトタイプ継承と呼ばれます。そこでは、それはとても簡単です、同意しますか?


割り当て時に製品に常に書かれているとは限りません。インスタンス固有のメンバーを初期化する必要があり、共有メンバーがプロトタイプに移行できることを明確にしていない。特にあなたは、インスタンスの特定の可変メンバを持っている場合:stackoverflow.com/questions/16063394/...
HMR

HMR:回答の例では、ben.food.push( "Hamburger"); lineは、次の理由によりプロトタイプオブジェクトのプロパティを変更します。2.)そのben.foodオブジェクトのpush関数が実行されます。私の回答でモードを書くことは、次のように明示的に値を設定したときを意味します。ben.food= ['Idly']; これにより、製品オブジェクトに常に新しいプロパティが作成され(まだそこにない場合)、値が割り当てられます。
Aravind、2014年

HMR:あなたのコメントをありがとう、それは私に私の理解を考えさせ、テストさせました。
Aravind 2014年

ben.foodを再度割り当てると、2番目の引数を使用してObject.defineProperty、Object.defineProperties、またはObject.createを使用して作成されない限り、食品メンバーがシャドウされます(常にではありません)。getter setterを作成したときに、re割り当てを使用してプロトタイプを変更することもできます(どのようなものか)。継承のパターンについて言えば、コンストラクター関数は理解するのが難しく、いくつかの大きな問題があることを理解していますが、それを理解することは良いことです。JavaScriptでの継承は、プロトタイプの設定で開始および終了するのではなく、初期化(コンストラクター)も(再)使用されます。
HMR 2014年

あなたの答えはプロトタイプを説明するのに適していますが、JavaScriptの継承とインスタンス固有のメンバーを単純化しすぎると誤って解釈される可能性があります。インスタンスでプロトタイプメンバーを変更すると他のインスタンスに影響する理由については、多くの質問が寄せられています。
HMR 2014年


10

次のkeyValueStoreオブジェクトを考えてみましょう:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

これを行うことで、このオブジェクトの新しいインスタンスを作成できます。

kvs = keyValueStore.create();

このオブジェクトの各インスタンスには、次のパブリックプロパティがあります。

  • data
  • get
  • set
  • delete
  • getLength

ここで、このkeyValueStoreオブジェクトのインスタンスを100個作成するとします。にもかかわらずgetsetdeletegetLengthこれらの100個のインスタンスごとに、まったく同じことを行いますが、すべてのインスタンスは、この関数の独自のコピーを持っています。

さて、あなたは1つだけ持っていることができれば想像しgetsetdeleteおよびgetLengthコピーを、各インスタンスは、同じ機能を参照します。これはパフォーマンスに優れ、必要なメモリも少なくなります。

これがプロトタイプの出番です。プロトタイプは、インスタンスによって継承されますがコピーされないプロパティの「青写真」です。つまり、オブジェクトのすべてのインスタンスのメモリに1回だけ存在し、それらのすべてのインスタンスで共有されます。

ここで、keyValueStoreオブジェクトをもう一度考えてみましょう。私はそれを次のように書き直すことができます:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

これは、keyValueStoreオブジェクトのすべてのメソッドがプロトタイプに入れられることを除いて、以前のバージョンのオブジェクトとまったく同じです。つまり、100個のインスタンスすべてが、それぞれ独自のコピーを持つ代わりに、これらの4つのメソッドを共有するということです。


9

概要:

  • 関数はJavaScriptのオブジェクトであるため、プロパティを持つことができます
  • (コンストラクタ)関数には常にプロトタイププロパティがあります
  • 関数をnewキーワード付きのコンストラクタとして使用すると、オブジェクトはプロトタイプを取得します。このプロトタイプへの参照__proto__は、新しく作成されたオブジェクトのプロパティにあります。
  • この__proto__プロパティはprototype、コンストラクター関数のプロパティを参照します。

例:

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

let me = new Person('willem');

console.log(Person.prototype) // Person has a prototype property

console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

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

Javascriptには、「プロトタイプ継承」と呼ばれるオブジェクトのプロパティを検索するメカニズムがあります。基本的には次のとおりです。

  • 最初に、プロパティがオブジェクト自体にあるかどうかがチェックされます。その場合、このプロパティが返されます。
  • プロパティがオブジェクト自体に配置されていない場合は、「プロトチェーンを登る」ことになります。基本的には、protoプロパティによって参照されるオブジェクトを調べます。そこでprotoが参照するオブジェクトでプロパティが利用可能かどうかをチェックします
  • プロパティがprotoオブジェクトに配置されていない場合は、protoチェーンからObjectオブジェクトまで上がります。
  • オブジェクトとそのプロトタイプチェーンのどこにもプロパティが見つからない場合は、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);

更新:

__proto__それはプロトタイプオブジェクトの参照を取得するより良い方法は以下のようになり、最新のブラウザで実装されているが、プロパティは、廃止されました:

Object.getPrototypeOf()


7

この種のものを理解するとき、私はいつもアナロジーが好きです。「プロトタイプの継承」は、プロトタイプの方がはるかに単純なパラダイムですが、私の意見では、クラスの低音の継承と比較するとかなり混乱しています。実際、プロトタイプでは継承はありません。そのため、名前自体は誤解を招きやすく、「委任」の一種です。

これを想像してみて....

あなたは高校に在籍しており、クラスに属していて今日クイズのクイズがありますが、回答を記入するペンがありません。どー!

あなたは、ペンを持っているかもしれない友達のフィニウスの隣に座っています。あなたが尋ねると、彼は彼の机を見回すことに失敗しましたが、「ペンを持っていません」と言うのではなく、彼は彼がペンを持っているかどうか彼が彼の他の友人ダープに確認する素敵な友人です。Derpは確かに予備のペンを持っていて、それをFinniusに返します。Finniusがあなたに渡して、クイズを完了します。Derpは、ペンをあなたに委託して使用したFinniusにペンを委託しました。

ここで重要なのは、あなたが彼と直接の関係を持っていないので、ダープはあなたにペンを与えないということです。

これは、プロトタイプがどのように機能するかを示す単純化された例であり、データのツリーから目的のものが検索されます。


3

__proto__プロトタイプおよびコンストラクタの関係を示す別のスキーム: ここに画像の説明を入力してください


1

既にオブジェクトを持っているだけですがObject.new、コンストラクター構文を使用するときにはまだオブジェクトがありません。


1

オブジェクトのプロトタイプ(を介してObject.getPrototypeOf(obj)、または非推奨の__proto__プロパティを介して利用可能)とprototypeコンストラクター関数のプロパティとの間には違いがあることを理解することが重要です。前者は各インスタンスのプロパティで、後者はコンストラクタのプロパティです。つまりObject.getPrototypeOf(new Foobar())、と同じオブジェクトを指しますFoobar.prototype

リファレンス:https : //developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes


0

プロトタイプは、作成し、新しいオブジェクトを既存のクローニングすることにより、オブジェクトを。したがって、プロトタイプについて考えるとき、実際に何かを作成する代わりに、何かを複製またはコピーすることを考えることができます。

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