javascript - 継承 - js prototype 書き方




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

私はそれが動的プログラミング言語ではありませんが、私は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

また、これらのslides本当に助けになりました。


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

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

プロトタイプを特別なvtableポインタと考えてください。一部のメンバーが元のクラスにない場合、プロトタイプは実行時に参照されます。


プロトタイプの7人のKoans

Ciro Sanが深い瞑想の後にMount Fire Foxを下ったとき、彼の心ははっきりと平穏だった。

しかし、彼の手は落ち着きがなく、それだけでブラシをつかんで、次の注意を書き留めました。

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

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

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

    これは、ES5のObject.getPrototypeOf()を介して取得できます。

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

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

obj.propertyを実行すると、JSはどこで.property探すのですか?

直観的には、古典的な継承はプロパティの検索に影響するはずです。

2)

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

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

  • obj.p = ...またはObject.defineProperty(obj, ...)追加された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
    

    これ.prototypeが使用される場所.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)

この図は、多くの言語定義済みのオブジェクトノードを示していますObject.prototypeObjectObject.prototypeFunctionおよびFunction.prototype 。 私たちの2行のコードは、 fFおよびF.prototype作成しただけです。

5) F.prototypeは通常F.prototypeから. 見上げる:

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

f.constructorを書くf.constructor 、JavaScriptはJavaScriptを実行し. ルックアップ:

  • f.constructor持たない
  • f.__proto__ === F.prototypef.__proto__ === F.prototype .constructor === Fがあるので、それを取る

f.constructor == Fの結果は直感的に正しい。なぜならFは古典的なOOP言語のようにfを設定するために使われるからである。

6)古典的継承構文は、プロトタイプチェーンを操作することによって達成することができる。

ES6はclassextendsキーワードを追加します。これは以前に考えられていたプロトタイプ操作の狂気のためのシンタックスシュガーです。

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://.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には通常の意味での継承はありませんが、プロトタイプチェーンがあります。

プロトタイプチェーン

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

プロトタイプに関数/変数を追加する利点は、すべてのインスタンスではなく、一度だけメモリ内になければならないということです。

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


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());

一方、私はsetAmountDue()、getAmountDue()をPersonで呼び出すことはできません。

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

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にしているので、私が間違っていると人々が私を修正することができます。


私はJavaScriptの教師としての役割を果たしています。プロトタイプのコンセプトは、私が教えるときは常に議論の対象となっています。 この概念を明確にするための良い方法を考え出すのにはしばらく時間がかかりましたが、今度はこのテキストでJavaScriptの.prototypeの仕組みを説明しようとしています。

これは非常に単純なプロトタイプベースのオブジェクトモデルであり、解説の間にサンプルとして考えられ、コメントはまだありません。

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キーワードを使用せずに同じことをやろうとしてます。

だから、このステップでは、 functionsobjects 、そしてthisキーワードはすべて私たちが持っています。

最初の質問は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オブジェクトまたはNode.js GLOBALです。 つまり、ブラウザーに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つの方法は、 __proto__という名前のJavaScriptオブジェクトで見つかるオブジェクトのprototypeを使用することです。これをサマリー部分で少し説明しようとしました。 だから私たちは次のようにして同様の結果を得ることができました:

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

しかし 、私たちが実際にやっていることは、リテラル( { ... } )を使ってJavaScriptオブジェクトを作成するたびにObject.prototypeに基づいて作成されるObject.prototypeObject.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__属性にアタッチするpropertiesObjectです。 だからあなたができることを確認する:

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

しかしここでの__proto__は、 personオブジェクトの最初のレベルで__proto__で定義されているすべてのプロパティにアクセスできることです(詳細については、要約部分を参照してください)。

これらの2つの方法のいずれかを使用すると、 thispersonオブジェクトを正確に指し示します。

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

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

そして

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機能を理解するための重要な初期ステップです。

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

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

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

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

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

var newObject = {};

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

私たちはここにprototypeオブジェクトに似た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"

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

newObject.getName();

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

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

Person.call(newObject, "George");

または

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

そのコンストラクタは、作成したばかりのオブジェクトであるため、コンストラクタは必要な処理を実行できます。

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

概要:

基本的に、関数上でnewキーワードを使用すると、それを呼び出すことになり、その関数はコンストラクタとして機能します。

new FunctionName()

JavaScriptは内部的にオブジェクトを作成し、空のハッシュを作成し、そのオブジェクトをコンストラクタに渡すと、コンストラクタは作成したオブジェクトであるため、コンストラクタは必要な処理を実行できます。関数内でreturn文を使用していない場合、またはreturn undefined;にした場合はreturn undefined; あなたの機能体の終わりに。

したがって、JavaScriptがオブジェクトのプロパティをルックアップする場合、最初に実行するのは、そのオブジェクトをルックアップすることです。 そして、秘密のプロパティ[[prototype]]これは通常、 __proto__が好きで、そのプロパティはJavaScriptが次に見えるものです。 また、 __proto__調べるときは、別のJavaScriptオブジェクトである限り、独自の__proto__属性を持ちます。次の__proto__がnullになるまで、 __proto__属性は上がります。 このObject.prototype属性がnullである唯一のJavaScript Object.prototypeオブジェクトは、 Object.prototypeオブジェクトです。

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

それがJavaScriptでの継承の仕組みです。

言い換えれば、関数のプロトタイププロパティを持っていて、新しいものを呼び出すと、そのプロパティのために新しく作成されたオブジェクトをJavaScriptが終了した後に、その関数の.prototypeを見て、このオブジェクト独自の内部プロトタイプを持っています。 等々。


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

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

これらは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。このプロトタイプは、すべての[[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


このスレッドを読んだら、JavaScript Prototype Chainと混乱していて、これらのチャートが見つかりました

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance

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

そして

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

これにはコードといくつかの素敵なダイアグラムの例が含まれています。

プロトタイプチェーンは最終的にObject.prototypeに落ちます。

プロトタイプチェーンは、サブクラスのプロトタイプを親クラスのオブジェクトに等しく設定することで、必要なときに技術的に延長することができます。

JavaScript Prototype Chainについて理解していただければ幸いです。


すべてのJavaScriptオブジェクトには、 [[Prototype]]と呼ばれる内部プロパティがあります。 obj.propNameまたはobj['propName']obj.propNameしてプロパティを検索し、そのオブジェクトにobj.hasOwnProperty('propName')を介してチェックできるプロパティがない場合、ランタイムはオブジェクト内のプロパティを検索します代わりに[[Prototype]]によって参照されます。 プロトタイプオブジェクトにもそのようなプロパティがない場合は、そのプロトタイプが順番にチェックされ、一致が見つかるまで、またはその終わりに達するまで元のオブジェクトのプロトタイプチェーンを歩きます。

JavaScript実装の中には、[[Prototype]]プロパティへの直接アクセスを許可するものがあります(例: __proto__という__proto__標準プロパティを使用)。 一般に、オブジェクトの作成中にオブジェクトのプロトタイプを設定することは可能です。 new Func()を使用して新しいオブジェクトを作成すると、オブジェクトの[[Prototype]]プロパティはFunc.prototypeによって参照されるオブジェクトに設定されます。

JavaScriptの継承システムは、これまでのようにプロトタイプであり、クラスベースではありませんが、これはJavaScriptでクラスをシミュレートすることを可能にします:

クラスとしてのコンストラクタ関数と、プロトタイプのプロパティ(つまり、コンストラクタ関数のprototypeプロパティによって参照されるオブジェクトのプロパティ)を、共有メンバ、つまり各インスタンスで同じメンバとして考えてください。 クラスベースのシステムでは、メソッドは各インスタンスに対して同じ方法で実装されるため、メソッドは通常プロトタイプに追加されますが、オブジェクトのフィールドはインスタンス固有であり、したがって構築中にオブジェクト自体に追加されます。


すべてのオブジェクトには[[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 )によって暗示されます。

注意:

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

obj_n.prop_X参照されているときに、「プロトタイプチェーン」を再帰的な規則として説明すると便利です。

obj_n.prop_X存在しない場合はobj_n+1.prop_Xobj_n+1 = obj_n.[[prototype]]

もし、prop_Xk番目のプロトタイプオブジェクトに最後に見つかった場合は

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

Javascriptオブジェクトの関係のグラフは、そのプロパティでここで見つけることができます:

http://jsobjects.org


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

new上の演算子を使うと、Tree functionそれをconstructor関数と呼びます。

すべてのJavaScript機能にはaがありprototypeます。あなたがログオンするとTree.prototype、あなたは...

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

Object.prototype

これには以下のようなものがあり.toString, .toValue, .hasOwnPropertyます...

__proto__私のmozillaを持ってきたものは非難されObject.getPrototypeOfていobject's prototypeます。

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

私たちにメソッドを追加しましょうTree prototype

私たちはそれを修正しRoot、そのfunctionブランチを追加しました。

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

我々はまた、追加することができますprimitivesまたはobjects当社へPrototype

child-tree私たちを私たちに追加しましょうTree

ここではTreeからChild継承しprototypeています。ここでやってObject.create()いることは、渡すものに基づいて新しいオブジェクトを作成するメソッドを使用していることですTree.prototype。このケースでは、ChildのTreeプロトタイプを、プロトタイプと同じに見える新しいオブジェクトに設定しています。次に、私たちがChild's constructor to Childそれを指摘しなければ、それを設定していTree()ます。

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

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

これinstanceChildbranchもともと利用可能なof とcall が作成されTreeます。私たちは実際に私たちbranchを定義していませんChild prototype。しかし、Root prototype子どもが継承しているところで。

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

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

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

これは裏で起こることです:// JavaScriptエンジンは何をしますか

これString objectは破壊される前の1つのステートメントのみに存在します(プロセスが呼び出されますautoboxing)。もう一度私たちに戻りましょうprototypal inheritance

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

prototypeJS の中のA は、yields別のものの親にあなたが持っているオブジェクトですobject[すなわち、委任] Delegationは、あなたが何かをすることができない場合、他の人にあなたのためにそれをするように指示します。

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

上記のフィドルを調べると、犬はtoStringメソッドにアクセスできますが、そのメソッドでは利用できませんが、代理するプロトタイプチェーンを介して利用できますObject.prototype

あなたが下のものを見ると、私たちはcall毎回利用可能な方法にアクセスしようとしていますfunction

https://jsfiddle.net/rknffckc/

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

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

上の図はちょっと複雑に見えますが、prototype chaining作品全体のイメージを引き出しています。これをゆっくりと歩みましょう:

2つのインスタンスがb1ありb2、そのコンストラクタはBarparentであり、parentはFooであり、プロトタイプchain identifyspeakviaの2つのメソッドがBarあります。Foo

https://jsfiddle.net/kbp7jr7n/

上記のコードを調べるとFoo、メソッドを持つコンストラクタと、メソッドを持つコンストラクタが生成されます。2つのインスタンスを作成し、その親の型はです。ofのメソッドを呼び出している間、私たちはチェーンを介して話している人を特定することができます。identify()BarspeakBarb1b2FoospeakBarprototype

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

IS 、のであるあなたが密接に見ればとのに関係しています。prototypeBarFooprototypeFooObjectprototypeFooObject.prototype

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

私はこのアドの情報がほしいと思っていますが、私はこれを理解するのに大きな可能性があることを知っています...単純な言葉で、それはオブジェクトにリンクされたオブジェクトです!


このタイプのものを理解するには、私はいつも類推が好きです。プロトタイプははるかに単純なパラダイムですが、 'Prototypical inheritance'は私の意見ではクラスベースの継承と比べてかなり混乱しています。実際にプロトタイプでは、実際には継承がないので、それ自体が誤解を招くような名前であり、より一種の「委任」です。

これを想像して....

あなたは高校に通っていて、授業中で今日はクイズがありますが、答えを記入するペンはありません。ドー!

あなたはペンを持っている可能性があるあなたの友人のFinniusの隣に座っています。あなたは尋ねると、彼は自分の机の周りをうまく見ることができませんが、 "私はペンがありません"と言っているのではなく、彼はペンがあれば他の友人Derpとチェックする素敵な友人です。Derpは本当に余分なペンを持っていて、それをFinniusに戻します。Finniusはあなたのクイズを完了するためにそれを渡します。Derpはペンを使用するためにあなたにペンを委任したFinniusにペンを委ねました。

ここで重要なのは、あなたが彼と直接関係がないので、Derpはあなたにペンを与えないということです。

これは、プロトタイプがどのように機能するかの簡単な例です。探しているものについてデータツリーが検索されます。



プロトタイプについての私の理解を教えてください。私はここで他の言語と継承を比較するつもりはありません。私は人々が言語の比較をやめ、その言語自体を理解することを望む。プロトタイプとプロトタイプの継承を理解することはとても簡単です。

プロトタイプは、製品を作成するためのモデルのようなものです。理解しておくべき重要なポイントは、プロトタイプとして別のオブジェクトを使用してオブジェクトを作成すると、プロトタイプと製品の間のリンクが永続的であることです。例えば:

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

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

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

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

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


次の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つのメソッドを共有することです。







prototype-oriented