私は動的プログラミング言語には興味がありませんが、私はかなりの割合の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
また、これらの スライド は本当に役に立ちました。
すべてのJavaScriptオブジェクトには、 [[Prototype]] という内部プロパティがあります。 obj.propName
またはobj['propName']
を介してプロパティを検索し、そのオブジェクトにそのようなプロパティがない場合(obj.hasOwnProperty('propName')
を介して確認できます)、ランタイムは代わりに[[Prototype]]によって参照されるオブジェクト内のプロパティを検索します。 prototype-objectにもそのようなプロパティがない場合は、そのプロトタイプが順番にチェックされます。したがって、一致するものが見つかるまで、またはその終わりに達するまで、元のオブジェクトの prototype-chain を歩きます。
一部のJavaScript実装では、[__proto__
]という名前の非標準プロパティなどを介して、[[Prototype]]プロパティに直接アクセスできます。一般に、オブジェクト作成中にオブジェクトのプロトタイプを設定することだけが可能です:new Func()
を介して新しいオブジェクトを作成する場合、オブジェクトの[[Prototype]]プロパティはFunc.prototype
によって参照されるオブジェクトに設定されます。
JavaScriptの継承システムはプロトタイプであり、クラスベースではありませんが、これによりJavaScriptでクラスをシミュレートすることができます。
コンストラクタ関数をクラスとして、プロトタイプのプロパティ(つまり、コンストラクタ関数のprototype
プロパティによって参照されるオブジェクトのプロパティ)を共有メンバ、つまり各インスタンスで同じメンバとして考えるだけです。クラスベースのシステムでは、メソッドは各インスタンスに対して同じ方法で実装されるため、メソッドは通常プロトタイプに追加されますが、オブジェクトのフィールドはインスタンス固有であり、したがって構築時にオブジェクト自体に追加されます。
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());
var Person = function (name) {
this.name = name;
};
Person.prototype.getName = function () {
return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
this.name = name;
};
Customer.prototype = new Person();
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());
言ったように私はPersonのsetAmountDue()、getAmountDue()を呼び出すことはできません。
//The following statement generates an error.
john.setAmountDue(1000);
これは、説明中にサンプルと見なされる非常に単純なプロトタイプベースのオブジェクトモデルであり、コメントはまだありません。
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
プロトタイプのコンセプトを検討する前に考慮しなければならない重要なポイントがいくつかあります。
最初の一歩を踏み出すには、JavaScript関数が実際にどのように機能するかを把握する必要があります-this
キーワードを使用する関数のようなクラスとして、または単に引数を持つ通常の関数として戻ります。
Person
オブジェクトモデルを作成するとします。しかし、このステップではprototype
およびnew
キーワードを使用せずに同じことを正確に行いますを試みます。
したがって、このステップではfunctions
、objects
およびthis
キーワードがすべて揃っています。
最初の質問はthis
キーワードを使用せずにnew
キーワードがどのように役立つかです。
それに答えるために、空のオブジェクトと、次のような2つの関数があるとします。
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
そして今new
キーワードを使用しないこれらの関数の使用方法。そのため、JavaScriptには3つの異なる方法があります。
Person("George");
getName();//would print the "George" in the console
この場合、これは現在のコンテキストオブジェクトになります。通常、これはブラウザのグローバルwindow
オブジェクトまたはNode.js
のGLOBAL
です。つまり、ブラウザのwindow.nameまたはNode.jsのGLOBAL.nameに値として「George」が含まれることになります。
-これを行う最も簡単な方法は、次のように空のperson
オブジェクトを変更することです。
person.Person = Person;
person.getName = getName;
このようにして、次のように呼び出すことができます。
person.Person("George");
person.getName();// -->"George"
そして今、person
オブジェクトは次のようになります:
Object {Person: function, getName: function, name: "George"}
-プロパティを付加する別の方法は、オブジェクトのprototype
を使用することです。この変数は、__proto__
という名前のJavaScriptオブジェクトで見つけることができます。要約部分。したがって、次の操作を行うことで同様の結果を得ることができます。
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
ただし、ここで注意が必要な点は、person
オブジェクトの最初のレベルで__proto__
で定義されているすべてのプロパティにアクセスできることです(詳細については概要の部分を参照してください)。
これらの2つの方法のいずれかを使用すると、this
がperson
オブジェクトを正確に指すことがわかります。
this
を提供する別の方法があり、これは call または apply を使用して関数を呼び出します。Apply()メソッドは、指定されたthis値と引数を配列(または配列のようなオブジェクト)として提供して関数を呼び出します。
そして
Call()メソッドは、この値と引数を個別に指定して関数を呼び出します。
私のお気に入りのこの方法で、次のような関数を簡単に呼び出すことができます。
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機能を理解するための重要な初期ステップです。
new
キーワードはどのように機能しますか?これは.prototype
機能を理解するための2番目のステップです。これはプロセスのシミュレーションに使用します。
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
この部分では、new
キーワードを使用するときに、prototype
キーワードとnew
を使用せずに、JavaScriptが実行するすべてのステップを実行しようとしています。したがって、new Person("George")
を実行すると、Person
関数がコンストラクターとして機能します。これらは、JavaScriptが1つずつ行います。
var newObject = {};
プロトタイプオブジェクトに似たmy_person_prototype
があります。
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
JavaScriptがプロトタイプで定義されたプロパティを実際に添付する方法ではありません。実際の方法は、プロトタイプチェーンの概念に関連しています。
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"
これで、my_person_prototype
でgetName
関数を呼び出すことができます。
newObject.getName();
次のようなサンプルでこれを行うことができます。
Person.call(newObject, "George");
または
Person.apply(newObject, ["George"]);
その場合、コンストラクターは何でもできます。なぜなら、そのコンストラクター内のthisは、作成されたばかりのオブジェクトだからです。
これで、他のステップをシミュレートする前の最終結果:オブジェクト{名前: "George"}
基本的に、関数でnewキーワードを使用すると、その関数を呼び出すことになり、その関数はコンストラクターとして機能します。
new FunctionName()
JavaScriptは内部的にオブジェクト、空のハッシュを作成し、そのオブジェクトをコンストラクターに渡します。コンストラクターは、コンストラクター内でthisが作成されたばかりのオブジェクトなので関数でreturnステートメントを使用していない場合、または関数本体の最後にreturn undefined;
を配置した場合、もちろんそのオブジェクトを提供します。
そのため、JavaScriptがオブジェクトのプロパティを検索する場合、最初に行うことは、そのオブジェクトのプロパティを検索することです。そして、秘密のプロパティがあります[[prototype]]
私たちは通常__proto__
のように持っています。そのプロパティはJavaScriptが次に見ているものです。そして、それが__proto__
を覗くと、それがまた別のJavaScriptオブジェクトである限り、それは独自の__proto__
属性を持ち、ポイントに到達するまで上下します。次の__proto__
はnullです。ポイントは、JavaScriptで__proto__
属性がnullである唯一のオブジェクトであるObject.prototype
オブジェクトです。
console.log(Object.prototype.__proto__===null);//true
それがJavaScriptでの継承の仕組みです。
つまり、関数のプロトタイププロパティがあり、その上で新しいプロパティを呼び出すと、JavaScriptがそのプロパティについてその新しく作成されたオブジェクトを見終わった後、関数の.prototype
を調べ、このオブジェクトが持つ可能性もあります独自の内部プロトタイプ。等々。
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
関数を持ちます。
以上が私の理解です。私はそれをコミュニティウィキにしているので、間違っていても人々は私を直すことができます。
Ciro Sanが深い瞑想の後にMount Fire Foxを降りたとき、彼の心ははっきりしていて平和でした。
しかし彼の手は落ち着かず、それだけで筆を掴んで次のメモを書き留めた。
0) 2つの異なることが "プロトタイプ"と呼ぶことができます。
obj.prototype
のようにprototypeプロパティ
プロトタイプの内部プロパティ。[[Prototype]]
ES5では として示されています。
ES5のObject.getPrototypeOf()
から取得できます。
Firefoxは__proto__
プロパティを通して拡張としてそれにアクセス可能にします。 ES6は現在言及している__proto__
のいくつかのオプションの要件。
1) これらの概念は質問に答えるために存在します:
obj.property
を実行すると、JSはどこで.property
を検索しますか?
直感的には、古典的な継承はプロパティ検索に影響を与えるはずです。
2)
__proto__
は、.
のようにドットのobj.property
プロパティの検索に使用されます。 .prototype
は、直接検索に使用されるnotです。new
を使用したオブジェクト作成時に__proto__
を決定するため、間接的にのみ使用されます。検索順序は次のとおりです。
obj
プロパティにobj.p = ...
またはObject.defineProperty(obj, ...)
を追加obj.__proto__
のプロパティobj.__proto__.__proto__
のプロパティなど__proto__
がnull
であれば、undefined
を返します。これはいわゆるプロトタイプチェーンです。
obj.hasOwnProperty('key')
とObject.getOwnPropertyNames(f)
で.
検索を避けることができます
3) obj.__proto__
を設定するには、主に2つの方法があります。
new
:
var F = function() {}
var f = new F()
new
は次のように設定しています。
f.__proto__ === F.prototype
Thisは.prototype
が使われる場所です。
Object.create
:
f = Object.create(proto)
セット:
f.__proto__ === proto
4) コード:
var F = function() {}
var f = new F()
次の図に対応しています。
(Function) ( F ) (f)
| ^ | | ^ |
| | | | | |
| | | | +-------------------------+ |
| |constructor | | | |
| | | +--------------+ | |
| | | | | |
| | | | | |
|[[Prototype]] |[[Prototype]] |prototype |constructor |[[Prototype]]
| | | | | |
| | | | | |
| | | | +----------+ |
| | | | | |
| | | | | +-----------------------+
| | | | | |
v | v v | v
(Function.prototype) (F.prototype)
| |
| |
|[[Prototype]] |[[Prototype]]
| |
| |
| +-------------------------------+
| |
v v
(Object.prototype)
| | ^
| | |
| | +---------------------------+
| | |
| +--------------+ |
| | |
| | |
|[[Prototype]] |constructor |prototype
| | |
| | |
| | -------------+
| | |
v v |
(null) (Object)
この図は、null
、Object
、Object.prototype
、Function
、およびFunction.prototype
のように、多くの言語の定義済みオブジェクトノードを示しています。 2行のコードで作成されたのはf
、F
およびF.prototype
だけです。
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
を持っているので、それを持っていこうF
はf
を構築するために使用されるので、結果f.constructor == F
は直感的に正しいです。古典的なOOP言語のように、フィールドを設定します。
6) 古典的な継承構文はプロトタイプチェーンを操作することで実現できます。
ES6では、class
および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.
(new C(1)).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
すべての事前定義オブジェクトを含まない簡略図
__proto__
(C)<---------------(D) (d)
| | | |
| | | |
| |prototype |prototype |__proto__
| | | |
| | | |
| | | +---------+
| | | |
| | | |
| | v v
|__proto__ (D.prototype)
| | |
| | |
| | |__proto__
| | |
| | |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype
このスレッドを読んだ後、私はJavaScript Prototype Chainと混同して、それからこれらのチャートを見つけました
http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance
プロトタイプチェーンによるJavaScriptの継承を示すのは明らかなチャートです
そして
http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/
これにはコードといくつかのNiceダイアグラムの例が含まれています。
プロトタイプチェーンは、最終的にはObject.prototypeにフォールバックします。
プロトタイプチェーンは、サブクラスのプロトタイプを親クラスのオブジェクトと等しく設定することによって、必要に応じて技術的に拡張することができます。
JavaScript Prototype Chainを理解していただければ幸いです。
すべてのオブジェクトは内部プロパティ[[Prototype]]を持ち、それを他のオブジェクトにリンクさせます。
object [[Prototype]] -> anotherObject
伝統的なJavaScriptでは、リンクされたオブジェクトは関数のprototype
プロパティです。
object [[Prototype]] -> aFunction.prototype
環境によっては、[[Prototype]]を__proto__
として公開しています。
anObject.__proto__ === anotherObject
オブジェクトを作成するときに[[Prototype]]リンクを作成します。
// (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;
new
ステートメントは、リンク先(Object.prototype
)自体を表示しません。代わりに、ターゲットはコンストラクタ(Object
)によって暗黙的に示されます。
覚えておいてください:
__proto__
として公開されることもあります。prototype
プロパティを持っています。new
で作成されたオブジェクトは、それらのコンストラクタのprototype
プロパティにリンクされています。prototype
プロパティは使われないでしょう。new
の代わりに Object.create を使用してください。この記事は長いです。しかし、JavaScriptの継承の「原型的」な性質に関するあなたの質問の大部分は明確にされると確信しています。そしてさらにもっと。記事全体を読んでください。
JavaScriptには基本的に2種類のデータ型があります
非オブジェクト
以下は非オブジェクトデータ型です。
typeof 演算子を使用すると、これらのデータ型は次のように返されます。
typeof "文字列リテラル"(または文字列リテラルを含む変数)=== 'string'
typeof 5(または任意の数値リテラル、または数値リテラルを含む変数、またはNaNまたはInfynity)=== 'number '
typeof true(またはfalseまたはtrueまたはfalse)を含む変数=== 'ブール値 '
typeof 未定義(または未定義の変数または未定義を含む変数)=== '未定義'
文字列 、 number および boolean のデータ型は、 Objects および Non objects の両方で表すことができます。それらのtypeofが常に=== 'object'であるオブジェクトとして表される。オブジェクトのデータ型を理解したら、これに戻ります。
オブジェクト
オブジェクトデータ型はさらに2つのタイプに分けられます。
関数型オブジェクト は、文字列 'function' を typeof 演算子で返すものです。 new演算子を使用して新しいオブジェクトを作成できるすべてのユーザー定義関数とすべてのJavaScript組み込みオブジェクトは、このカテゴリーに分類されます。例えば。
したがって、 typeof(Object) === typeof(String) === typeof(Number) === typeof (ブール値) === typeof(配列) === typeof(RegExp) === typeof(関数) === typeof(UserDefinedFunction) === '関数'
すべての関数型オブジェクトは、実際には組み込みのJavaScriptオブジェクト Function のインスタンスです( Function オブジェクトを含む、つまり再帰的に定義されます)。 。これらのオブジェクトは次のように定義されているかのようです。
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")
前述のように、関数型オブジェクトは、 new演算子 を使用してさらに新しいオブジェクトを作成できます。たとえば、 Object 、 String 、 Number 、 Boolean 、 Array 、 RegExpのオブジェクト または 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"はoperator newを使用してオブジェクトをさらに作成することはできません。だから以下は間違っている
var b=new a() //error. a is not typeof==='function'
組み込みオブジェクト Math は typeof === 'object' です。したがって、Math型の新しいオブジェクトをnew演算子で作成することはできません。
var b=new Math() //error. Math is not typeof==='function'
また、 Object 、 Array 、および RegExp 関数は、 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.
関数型オブジェクトは新しいオブジェクトを作成することができるので、コンストラクタとも呼ばれます。
すべての コンストラクタ/関数 (組み込みかユーザー定義かを問わず)自動的に定義された "prototype" というプロパティを持ち、その値はデフォルトでオブジェクトとして設定されます。このオブジェクト自体に "constructor" というプロパティがあり、これはデフォルトで コンストラクタ/ Function を逆参照します。
例えば関数を定義するとき
function UserDefinedFunction()
{
}
次は自動的に起こります
UserDefinedFunction.prototype={constructor:UserDefinedFunction}
この "prototype"プロパティ は、 関数型オブジェクト にのみ存在します( 非関数型オブジェクト には存在しません)。
これは、 (new演算子を使用して)新しいオブジェクトが作成されると、コンストラクタ関数の現在のプロトタイプオブジェクトからすべてのプロパティとメソッドを継承するためです。つまり、 内部参照 コンストラクタ関数の現在のプロトタイプオブジェクトによって参照されるオブジェクトを参照する、新しく作成されたオブジェクト内に作成されます。
継承されたプロパティを参照するためにオブジェクト内に作成されるこの "内部参照" は、 オブジェクトのプロトタイプ (コンストラクタの "prototype" によって参照されるオブジェクトを参照する)として知られます。プロパティが、それとは異なります。任意のオブジェクト(関数または非関数)の場合、これは Object.getPrototypeOf() methodを使用して取得できます。このメソッドを使うと、オブジェクトのプロトタイプチェーンをたどることができます。
また、 作成されるすべてのオブジェクト ( 関数型 または 非関数型 )には、 "コンストラクタ" プロパティが継承されています。コンストラクタ関数のprototypeプロパティによって参照されるオブジェクト。デフォルトでは、この "constructor" プロパティは、それを作成した コンストラクタ関数 を参照します( コンストラクタ関数の default "prototype"が変更されていない場合)。
すべての関数型オブジェクトに対して、コンストラクタ関数は常にfunction Function(){}
非関数型オブジェクト(Javascript Built in Mathオブジェクトなど)の場合、コンストラクタ関数はそれを作成した関数です。 Math object itfunction Object(){}です。
上記で説明した概念はすべて、サポートするコードがないと理解するのが少し面倒です。この概念を理解するために、次のコードを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))
さまざまなオブジェクトのプロトタイプチェーンは次のようになります。
プロトタイプなしでオブジェクトを作成するには、次のようにします。
var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null
コンストラクタのprototypeプロパティを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
この記事のまとめに従う
関数型オブジェクト のみ、 演算子new を使用して新しいオブジェクトを作成できます。このようにして作成されたオブジェクトは、 非関数型 オブジェクトです。 非関数型オブジェクト は、 演算子new を使用してさらにオブジェクトを作成することはできません。
すべての 関数型オブジェクト には、デフォルトで "prototype" プロパティがあります。この "prototype" プロパティは、デフォルトで 関数型オブジェクト 自体を参照する "コンストラクタ" プロパティを持つオブジェクトを参照します。
すべてのオブジェクト( 関数型 および 非関数型 )には、デフォルトで 関数型オブジェクト / コンストラクタ を参照する「コンストラクタ」プロパティがあります。それはそれを作成しました。
内部的に作成されるすべてのオブジェクトは、それを作成したコンストラクタの "prototype" プロパティによって参照されるオブジェクトを参照します。このオブジェクトは、作成されたオブジェクトのプロトタイプとして知られています(これは、それが参照する関数型オブジェクトの "prototype"プロパティとは異なります)。このようにして、作成されたオブジェクトはコンストラクタの "prototype"プロパティによって参照されるオブジェクトで定義されたメソッドとプロパティに直接アクセスすることができます(オブジェクト作成時)。
オブジェクトのプロトタイプ (およびその継承プロパティ名)は、 Object.getPrototypeOf() メソッドを使用して取得できます。実際、このメソッドは、オブジェクトのプロトタイプチェーン全体をナビゲートするために使用できます。
すべてのオブジェクトのプロトタイプチェーンは、最終的にObject.prototypeまでさかのぼります(オブジェクトがObject.create(null)を使用して作成されている場合、そのオブジェクトにプロトタイプはありません)。
typeof(new Array())=== 'object' は言語の仕様によるもので、 Douglas Crockfordによる指摘の誤りではありません
コンストラクタのprototypeプロパティをnull(または未定義、number、true、false、string)に設定しても、nullプロトタイプのオブジェクトは作成されません。そのような場合、新しく作成されたオブジェクトのプロトタイプはObject.prototypeに設定され、そのコンストラクターは関数Objectに設定されます。
お役に立てれば。
Javascriptには通常の意味での継承はありませんが、プロトタイプチェーンがあります。
オブジェクトのメンバーがそのオブジェクト内に見つからない場合は、プロトタイプチェーンでそれを探します。チェーンは他のオブジェクトで構成されています。特定のインスタンスのプロトタイプは、__proto__
変数を使用してアクセスできます。 JavaScriptではクラスとインスタンスの間に違いはないため、すべてのオブジェクトに1つあります。
プロトタイプに関数/変数を追加する利点は、すべてのインスタンスではなく、1回だけメモリに存在する必要があることです。
プロトタイプチェーンは他の多くのオブジェクトで構成できるため、継承にも役立ちます。
prototypal
継承の概念は、多くの開発者にとって最も複雑なものの1つです。 prototypal inheritance
をよりよく理解するために、問題の根本を理解しようとしましょう。 plain
関数から始めましょう。
Tree function
でnew
演算子を使用する場合は、それをconstructor
関数として呼び出します。
すべてのJavaScript
関数にはprototype
があります。 Tree.prototype
をログに記録すると、次のようになります。
上記のconsole.log()
の出力を見れば、Tree.prototype
のコンストラクタプロパティと__proto__
プロパティも見ることができます。 __proto__
は、このprototype
の基になっているfunction
を表します。これはまだinheritance
が設定されていない単なるJavaScript function
であるため、JavaScriptに組み込まれたObject prototype
を参照しています...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
これには.toString, .toValue, .hasOwnProperty
などのようなものがあります。
私のmozillaを持ってきた__proto__
は廃止予定で、Object.getPrototypeOf
を取得するためにobject's prototype
メソッドに置き換えられました。
Object.getPrototypeOf(Tree.prototype); // Object {}
Tree
prototype
にメソッドを追加しましょう。
Root
を修正し、それにfunction
ブランチを追加しました。
つまり、instance
のTree
を作成するときは、そのbranch
メソッドを呼び出すことができます。
primitives
またはobjects
をPrototype
に追加することもできます。
Tree
にchild-tree
を追加しましょう。
ここでChild
はTreeからのprototype
を継承しています。ここで行っていることは、Object.create()
メソッドを使用して、渡された内容に基づいて新しいオブジェクトを作成することです。ここではTree.prototype
です。この場合、ChildのプロトタイプをTree
プロトタイプと同じように見える新しいオブジェクトに設定します。次にChild's constructor to Child
を設定します。そうでなければTree()
を指します。
Child
は独自のprototype
を持ち、その__proto__
はTree
を指し、Tree's prototype
はベースのObject
を指します。
Child
|
\
\
Tree.prototype
- branch
|
|
\
\
Object.prototype
-toString
-valueOf
-etc., etc.
今度はinstance
をChild
として作成し、元々branch
で利用可能だったTree
を呼び出します。 Child prototype
で実際にbranch
を定義していません。しかし、Childが継承しているRoot prototype
の中です。
JSではすべてがオブジェクトではなく、すべてがオブジェクトのように振る舞うことができます。
Javascript
はstrings, number, booleans, undefined, null.
のようなプリミティブを持ちます。それらはobject(i.e reference types)
ではありませんが、確かにobject
のように振る舞うことができます。ここで例を見てみましょう。
このリストの最初の行で、primitive
という文字列値がnameに割り当てられています。 2行目はnameをobject
のように扱い、ドット表記を使用してcharAt(0)
を呼び出します。
これは舞台裏で起こることです: // JavaScript
エンジンがすること
String object
は、破棄される前の1つのステートメントに対してのみ存在します(autoboxing
というプロセス)。 prototypal
inheritance
に戻りましょう。
Javascript
は、 delegation
に基づくprototypes
による継承をサポートしています。Function
には、別のオブジェクトを参照するprototype
プロパティがあります。properties/functions
は、object
自体から、または存在しない場合は prototype
チェーンを介して調べられます。JSのprototype
は、他のyields
の親にあなたをobject
するオブジェクトです。 [.. .. delegation]Delegation
は、あなたが何かをすることができない場合、他の人にあなたに代わってそれをするように言うでしょう。
https://jsfiddle.net/say0tzpL/1/ /
上記のフィドルを調べると、dogはtoString
メソッドにアクセスできますが、そのメソッドでは使用できませんが、Object.prototype
に委任するプロトタイプチェーンを介して使用できます。
以下のものを見れば、私たちはすべてのcall
で利用可能なfunction
メソッドにアクセスしようとしています。
https://jsfiddle.net/rknffckc/ /
上記のフィドルを調べると、Profile
関数はcall
メソッドにアクセスできますが、そのメソッドでは利用できませんが、Function.prototype
に委任するプロトタイプチェーンを介して利用できます
注:prototype
は関数コンストラクタのプロパティですが、__proto__
は関数コンストラクタから構築されたオブジェクトのプロパティです。すべての関数は、値が空のprototype
であるobject
プロパティを持っています。関数のインスタンスを作成すると、その参照が関数constructor
のプロトタイプである内部プロパティ[[Prototype]]
または__proto__
を取得します。
上の図は少し複雑に見えますが、prototype chaining
がどのように機能するかについて全体像を明らかにしています。これをゆっくり見ていきましょう。
2つのインスタンスb1
とb2
があり、それらのコンストラクターはBar
、parentはFooで、プロトタイプチェーンidentify
とspeak
からBar
とFoo
までの2つのメソッドがあります。
https://jsfiddle.net/kbp7jr7n/
上記のコードを調べると、メソッドidentify()
を持つFoo
コンストラクタと、メソッドBar
を持つspeak
があります。親の型がBar
である2つのFoo
インスタンスb1
とb2
を作成します。 speak
のBar
メソッドを呼び出している間に、prototype
チェーンを介して、誰が通話を呼び出しているのかを識別することができます。
Bar
は、Foo
で定義されているprototype
のすべてのメソッドを持つようになりました。 Object.prototype
とFunction.prototype
と、それらがどのように関連しているかをさらに深く理解しましょう。 Foo
のコンストラクタを調べると、Bar
とObject
はFunction constructor
です。
prototype
のBar
はFoo
、prototype
のFoo
はObject
であり、よく見るとprototype
のFoo
はObject.prototype
に関連しています。
これを閉じる前に、ここで小さなコードを上記のすべてをまとめたものにラップしましょう。ここではinstanceof
演算子を使用して、object
のprototype
チェーンにprototype
のconstructor
プロパティが含まれているかどうかをチェックしています。
私はこれがいくつかの情報を追加することを願っています、私はこのちょっと把握するのが大きいかもしれないことを知っています...簡単な言葉でそれそれはただオブジェクトにリンクされたオブジェクトです!!!!
この「.prototype」プロパティの正確な目的は何ですか?
標準クラスへのインターフェースは拡張可能になります。たとえば、Array
クラスを使用していて、すべての配列オブジェクトにカスタムシリアライザを追加する必要もあります。サブクラスをコーディングするのに時間がかかるでしょうか、それともコンポジションを使うのですか... prototypeプロパティは、クラスに利用可能なメンバー/メソッドの正確なセットをユーザーに制御させることによってこれを解決します。
プロトタイプを追加のvtableポインタとして考えてください。一部のメンバーが元のクラスにない場合、プロトタイプは実行時に調べられます。
プロトタイプチェーンを2つのカテゴリに分類するのに役立つかもしれません。
コンストラクタを考えてください。
function Person() {}
Object.getPrototypeOf(Person)
の値は関数です。実際、それはFunction.prototype
です。 Person
は関数として作成されたので、すべての関数が持つのと同じプロトタイプ関数オブジェクトを共有します。これはPerson.__proto__
と同じですが、そのプロパティは使用しないでください。とにかく、Object.getPrototypeOf(Person)
を使えば、プロトタイプチェーンと呼ばれるもののはしごを効果的に歩き回ることができます。
上方向のチェーンは次のようになります。
Person
→Function.prototype
→Object.prototype
(エンドポイント)
重要なことは、このプロトタイプチェーンはPerson
がconstructにできるオブジェクトとはほとんど関係がないということです。それらの構築されたオブジェクトはそれら自身のプロトタイプチェーンを持ち、このチェーンは潜在的に上記のものと共通の親密な先祖を持つことができません。
例えば、このオブジェクトを取ります:
var p = new Person();
pはPersonと直接のプロトタイプチェーン関係を持ちません。彼らの関係は違うものです。オブジェクトpは独自のプロトタイプチェーンを持ちます。 Object.getPrototypeOf
を使用すると、チェーンは次のようになります。
p
→Person.prototype
→Object.prototype
(エンドポイント)
このチェーンには関数オブジェクトはありません(ただし、それは可能です)。
そのためPerson
は2種類のチェーンに関連しているように見えます。あるチェーンから別のチェーンに「ジャンプ」するには、次のようにします。
.prototype
:コンストラクタのチェーンから作成オブジェクトのチェーンへジャンプします。したがって、このプロパティは関数オブジェクトに対してのみ定義されます(new
は関数に対してのみ使用できます)。
.constructor
:作成オブジェクトのチェーンからコンストラクタのチェーンへジャンプします。
これは、関連する2つのプロトタイプチェーンを視覚的に表したもので、列として表されています。
要約すると:
prototype
プロパティはsubject'sプロトタイプチェーンについての情報を与えませんが、オブジェクトによって作成された _ subjectについての情報を与えます。
プロパティprototype
の名前が混乱を招く可能性があるのは当然のことです。このプロパティの名前がprototypeOfConstructedInstances
またはその行に沿っている場合は、より明確になっているはずです。
2つのプロトタイプチェーンを行き来することができます。
Person.prototype.constructor === Person
この対称性は、prototype
プロパティに別のオブジェクトを明示的に代入することで破られる可能性があります(詳細は後述)。
Person.prototype
は、関数Person
が作成されたときに同時に作成されたオブジェクトです。そのコンストラクタは実際にはまだ実行されていませんが、それはコンストラクタとしてPerson
を持っています。したがって、2つのオブジェクトが同時に作成されます。
Person
自体どちらもオブジェクトですが、役割は異なります。関数オブジェクトconstruct、もう一方のオブジェクトは、その関数が構築するすべてのオブジェクトのプロトタイプを表します。プロトタイプオブジェクトは、そのプロトタイプチェーン内の構築されたオブジェクトの親になります。
関数はオブジェクトでもあるので、それはそれ自身のプロトタイプチェーンの中にそれ自身の親も持っています、しかしこれら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ステップ長くなりました。
t
→p
→Person.prototype
→Object.prototype
(エンドポイント)
もう1つのプロトタイプチェーンはもう存在しません。Thief
とPerson
は、それらのプロトタイプチェーンで同じ親を共有する兄弟です。
Person
}Thief
}→Function.prototype
→Object.prototype
(終点)
それから以前に提示されたグラフィックはこれに拡張することができます(オリジナルのThief.prototype
は除外されます):
青い線はプロトタイプチェーンを表し、他の色付きの線は他の関係を表します。
The Object-Oriented JavaScript Definitive Guide -質問の非常に簡潔で明確な〜30minのビデオの説明(プロトタイプ継承トピックは 5:45 から始まりますが、むしろビデオ全体を聞いてください)。このビデオの作成者は、JavaScriptオブジェクトビジュアライザーのWebサイトも作成しました http://www.objectplayground.com/ .
obj_n.prop_X
が参照されているときの再帰的な慣習として、「プロトタイプチェーン」を説明することは有用であると思いました。
obj_n.prop_X
が存在しない場合は、obj_n+1.prop_X
を確認してくださいobj_n+1 = obj_n.[[prototype]]
最後にk番目のプロトタイプオブジェクトでprop_X
が見つかった場合
obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X
Javascriptオブジェクトのプロパティによるそれらの関係のグラフをここで見つけることができます:
コンストラクタがオブジェクトを作成すると、そのオブジェクトはプロパティ参照を解決する目的で、コンストラクタの「prototype」プロパティを暗黙的に参照します。コンストラクタの「prototype」プロパティはプログラム式constructor.prototypeによって参照でき、オブジェクトのプロトタイプに追加されたプロパティは継承を通じて、プロトタイプを共有するすべてのオブジェクトによって共有されます。
説明が必要な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
最も重要な.prototype
sの1つは、 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)
do をFunction.prototype
に代入するときは、プロトタイプチェーンを拡張して別のオブジェクトを含めるだけです。それは片方向リンクリストへの挿入のようなものです。
これは基本的に[[Prototype]]
チェーンを変更して、Function.prototype
に割り当てられたオブジェクトで定義されているプロパティが、その関数によって作成された任意のオブジェクトから見えるようにします。
[1:誰もが混乱することはありません。多くの実装で __proto__
プロパティ を介して利用可能になりました。
[2]: null
以外のすべて。
プロトタイプについて理解してください。ここで継承を他の言語と比較するつもりはありません。私は、人々が言語の比較をやめて、その言語をそれ自体として理解するようにすることを望みます。プロトタイプとプロトタイプの継承を理解するのはとても簡単です。
プロトタイプはモデルのようなもので、それに基づいて製品を作成します。理解しておくべき重要な点は、プロトタイプとして別のオブジェクトを使用してオブジェクトを作成する場合、プロトタイプと製品の間のリンクは永続的であるということです。例えば:
var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5
すべてのオブジェクトは[[prototype]]と呼ばれる内部プロパティを含み、これはObject.getPrototypeOf()
関数によってアクセスすることができます。 Object.create(model)
は新しいオブジェクトを作成し、その[[prototype]]プロパティをオブジェクト model に設定します。それであなたがObject.getPrototypeOf(product)
をするとき、あなたはオブジェクト model を得るでしょう。
product のプロパティは次のように処理されます。
プロトタイププロパティを使用してオブジェクトをこのようにリンクすることは、プロトタイプ継承と呼ばれます。それはとても単純です、同意しますか?
次の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個作成したとします。 get
、set
、delete
、getLength
は、これら100個のインスタンスそれぞれに対してまったく同じことを実行しますが、すべてのインスタンスに独自のこの関数のコピーがあります。
さて、get
、set
、delete
、およびgetLength
のコピーを1つだけ持つことができ、各インスタンスがその同じ関数を参照するとします。これはパフォーマンスに優れていて、必要なメモリが少なくて済みます。
それがプロトタイプが登場するところです。プロトタイプは継承されますが、インスタンスによってコピーされないプロパティの「青写真」です。したがって、これは、オブジェクトのすべてのインスタンスに対してメモリ内に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つのメソッドを共有しているということです。
JavaScriptプロトタイプベースの継承 /より良い写真付きで説明するもう1つの試み
私はそれがこの種のものを理解することになるといつもアナロジーが好きです。プロトタイプははるかに単純なパラダイムですが、 'プロトタイプの継承'は私の考えではクラスベースの継承と比較するとかなり混乱します。実際にはプロトタイプでは、継承はまったくありません。そのため、名前自体が誤解を招くことになりますが、それは「委任」の一種です。
想像してみてください。
あなたは高校生です、そして、あなたはクラスにいて、そして今日予定されているクイズを持っています、しかしあなたはあなたの答えを記入するペンを持っていません。やあ!
あなたはペンを持っているかもしれないあなたの友人Finniusの隣に座っています。あなたが尋ねると、彼は机の周りを見回して失敗しましたが、「私はペンを持っていません」と言う代わりに、彼はもう一方の友人Derpと彼がペンを持っているか調べます。 Derpは確かに予備のペンを持っていて、それをFinniusに渡し、Finniusはあなたにそれを渡してクイズを完成させます。 DerpはそのペンをFinniusに任せました。
ここで重要なことは、あなたが彼と直接の 関係 を持っていないので、Derpはあなたにペンを渡さないことです。
これは、プロトタイプがどのように機能するかの簡単な例です。ここでは、探しているものについてデータのツリーが検索されます。
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は 'プロトタイプの継承' と呼ばれるオブジェクトのプロパティを調べるときのメカニズムを持っています。
例えば:
function Person(name) {
this.name = name;
}
let mySelf = new Person('Willem');
console.log(mySelf.__proto__ === Person.prototype);
console.log(mySelf.__proto__.__proto__ === Object.prototype);
それは、あなたが既にObject.new
を持つオブジェクトを持っているということですが、コンストラクタ構文を使うとき、あなたはまだオブジェクトを持っていません。
プロトタイプ は 新しいオブジェクトを作成する 既存の オブジェクトを複製することによって 。つまり、プロトタイプについて考えるときには、 クローン作成または作成 それを作成するのではなく、コピーを作成することができます。
オブジェクトのプロトタイプ(Object.getPrototypeOf(obj)
または非推奨のobj.__proto__
プロパティを通じて利用可能です)とコンストラクタ関数のprototypeプロパティには違いがあることを理解することが重要です。前者は各インスタンスのプロパティ、後者はコンストラクタのプロパティです。つまり、Object.getPrototypeOf(new Foobar())
はFoobar.prototype
と同じオブジェクトを参照します。
参照: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes