web-dev-qa-db-ja.com

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

私は動的プログラミング言語には興味がありませんが、私はかなりの割合の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

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

1945
John Leidegren

すべての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プロパティによって参照されるオブジェクトのプロパティ)を共有メンバ、つまり各インスタンスで同じメンバとして考えるだけです。クラスベースのシステムでは、メソッドは各インスタンスに対して同じ方法で実装されるため、メソッドは通常プロトタイプに追加されますが、オブジェクトのフィールドはインスタンス固有であり、したがって構築時にオブジェクト自体に追加されます。

958
Christoph

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);
1774
stivlo

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

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

プロトタイプのコンセプトを検討する前に考慮しなければならない重要なポイントがいくつかあります。

1- JavaScript関数の実際の動作:

最初の一歩を踏み出すには、JavaScript関数が実際にどのように機能するかを把握する必要があります-thisキーワードを使用する関数のようなクラスとして、または単に引数を持つ通常の関数として戻ります。

Personオブジェクトモデルを作成するとします。しかし、このステップではprototypeおよびnewキーワードを使用せずに同じことを正確に行いますを試みます。

したがって、このステップでは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.jsGLOBALです。つまり、ブラウザのwindow.nameまたはNode.jsのGLOBAL.nameに値として「George」が含まれることになります。

b。 attachそれらをオブジェクトに、プロパティとして

-これを行う最も簡単な方法は、次のように空の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つの方法のいずれかを使用すると、thispersonオブジェクトを正確に指すことがわかります。

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


2- 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つずつ行います。

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

var newObject = {};

b。 JavaScriptが行う次のステップは、attachで、新しく作成されたオブジェクトへのすべてのプロトタイプオブジェクトです。

プロトタイプオブジェクトに似た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_prototypegetName関数を呼び出すことができます。

newObject.getName();

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

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

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での継承の仕組みです。

The prototype chain

つまり、関数のプロトタイププロパティがあり、その上で新しいプロパティを呼び出すと、JavaScriptがそのプロパティについてその新しく作成されたオブジェクトを見終わった後、関数の.prototypeを調べ、このオブジェクトが持つ可能性もあります独自の内部プロトタイプ。等々。

173
Mehran Hatami

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関数を持ちます。

以上が私の理解です。私はそれをコミュニティウィキにしているので、間違っていても人々は私を直すことができます。

73
Ramesh

プロトタイプの7つのコアンス

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)

この図は、nullObjectObject.prototypeFunction、およびFunction.prototypeのように、多くの言語の定義済みオブジェクトノードを示しています。 2行のコードで作成されたのはfFおよび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を持っているので、それを持っていこう

Ffを構築するために使用されるので、結果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*[[protytype]]* and <code>prototype</code> property of function objects

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

そして 

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

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

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

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

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

65
rockXrock

すべてのオブジェクトは内部プロパティ[[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 を使用してください。
37
sam

この記事は長いです。しかし、JavaScriptの継承の「原型的」な性質に関するあなたの質問の大部分は明確にされると確信しています。そしてさらにもっと。記事全体を読んでください。

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

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

非オブジェクト

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

  • 文字列
  • 数(NaNとInfinityを含む)
  • ブール値(true、false)  
  • 未定義

typeof 演算子を使用すると、これらのデータ型は次のように返されます。 

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

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

typeof true(またはfalseまたはtrueまたはfalse)を含む変数=== 'ブール値 '

typeof 未定義(または未定義の変数または未定義を含む変数)=== '未定義'

文字列 number および boolean のデータ型は、 Objects および Non objects の両方で表すことができます。それらのtypeofが常に=== 'object'であるオブジェクトとして表される。オブジェクトのデータ型を理解したら、これに戻ります。

オブジェクト

オブジェクトデータ型はさらに2つのタイプに分けられます。

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

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

  • オブジェクト
  • 文字列  
  •  
  • ブール値
  • 配列  
  • 型付き配列
  • 正規表現
  • 機能  
  • New演算子を使用して新しいオブジェクトを作成できるその他すべての組み込みオブジェクト
  • 関数 UserDefinedFunction (){/ *ユーザー定義コード* /}

したがって、 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))

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

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

プロトタイプなしでオブジェクトを作成するには、次のようにします。

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

この記事のまとめに従う

  • オブジェクトには2つのタイプがあります。 関数タイプ および 非関数タイプ
  • 関数型オブジェクト のみ、 演算子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に設定されます。 

お役に立てれば。

26
Arup Hore

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

プロトタイプチェーン

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

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

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

25
Georg Schölly

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

enter image description here

Tree functionnew演算子を使用する場合は、それをconstructor関数として呼び出します。 

enter image description here

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

enter image description here

上記の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メソッドに置き換えられました。 

enter image description here

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

Treeprototypeにメソッドを追加しましょう。 

enter image description here

Rootを修正し、それにfunctionブランチを追加しました。 

enter image description here

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

enter image description here

primitivesまたはobjectsPrototypeに追加することもできます。 

enter image description here

Treechild-treeを追加しましょう。 

enter image description here

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

enter image description here

Childは独自のprototypeを持ち、その__proto__Treeを指し、Tree's prototypeはベースのObjectを指します。 

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

今度はinstanceChildとして作成し、元々branchで利用可能だったTreeを呼び出します。 Child prototypeで実際にbranchを定義していません。しかし、Childが継承しているRoot prototypeの中です。 

enter image description here

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

Javascriptstrings, number, booleans, undefined, null.のようなプリミティブを持ちます。それらはobject(i.e reference types)ではありませんが、確かにobjectのように振る舞うことができます。ここで例を見てみましょう。

enter image description here

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

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

enter image description here

String objectは、破棄される前の1つのステートメントに対してのみ存在します(autoboxingというプロセス)。 prototypalinheritanceに戻りましょう。 

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

JSのprototypeは、他のyieldsの親にあなたをobjectするオブジェクトです。 [.. .. delegation]Delegationは、あなたが何かをすることができない場合、他の人にあなたに代わってそれをするように言うでしょう。

enter image description here

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

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

enter image description here

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

enter image description here

https://jsfiddle.net/rknffckc/ /

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

enter image description here

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

enter image description here

上の図は少し複雑に見えますが、prototype chainingがどのように機能するかについて全体像を明らかにしています。これをゆっくり見ていきましょう。

2つのインスタンスb1b2があり、それらのコンストラクターはBar、parentはFooで、プロトタイプチェーンidentifyspeakからBarFooまでの2つのメソッドがあります。

enter image description here

https://jsfiddle.net/kbp7jr7n/

上記のコードを調べると、メソッドidentify()を持つFooコンストラクタと、メソッドBarを持つspeakがあります。親の型がBarである2つのFooインスタンスb1b2を作成します。 speakBarメソッドを呼び出している間に、prototypeチェーンを介して、誰が通話を呼び出しているのかを識別することができます。 

enter image description here

Barは、Fooで定義されているprototypeのすべてのメソッドを持つようになりました。 Object.prototypeFunction.prototypeと、それらがどのように関連しているかをさらに深く理解しましょう。 Fooのコンストラクタを調べると、BarObjectFunction constructorです。

enter image description here

prototypeBarFooprototypeFooObjectであり、よく見るとprototypeFooObject.prototypeに関連しています。

enter image description here

これを閉じる前に、ここで小さなコードを上記のすべてをまとめたものにラップしましょう。ここではinstanceof演算子を使用して、objectprototypeチェーンにprototypeconstructorプロパティが含まれているかどうかをチェックしています。 

enter image description here

私はこれがいくつかの情報を追加することを願っています、私はこのちょっと把握するのが大きいかもしれないことを知っています...簡単な言葉でそれそれはただオブジェクトにリンクされたオブジェクトです!!!! 

22
Thalaivar

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

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

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

20
dirkgently

プロトタイプチェーンを2つのカテゴリに分類するのに役立つかもしれません。

コンストラクタを考えてください。

 function Person() {}

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

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

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

重要なことは、このプロトタイプチェーンはPersonconstructにできるオブジェクトとはほとんど関係がないということです。それらの構築されたオブジェクトはそれら自身のプロトタイプチェーンを持ち、このチェーンは潜在的に上記のものと共通の親密な先祖を持つことができません。

例えば、このオブジェクトを取ります:

var p = new Person();

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

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

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

そのためPersonは2種類のチェーンに関連しているように見えます。あるチェーンから別のチェーンに「ジャンプ」するには、次のようにします。

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

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

これは、関連する2つのプロトタイプチェーンを視覚的に表したもので、列として表されています。

enter image description here

要約すると:

prototypeプロパティはsubject'sプロトタイプチェーンについての情報を与えませんが、オブジェクトによって作成された _ subjectについての情報を与えます。 

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

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

Person.prototype.constructor === Person

この対称性は、prototypeプロパティに別のオブジェクトを明示的に代入することで破られる可能性があります(詳細は後述)。

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

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

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

どちらもオブジェクトですが、役割は異なります。関数オブジェクト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ステップ長くなりました。

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

もう1つのプロトタイプチェーンはもう存在しません。ThiefPersonは、それらのプロトタイプチェーンで同じ親を共有する兄弟です。

Person}
Thief}→Function.prototypeObject.prototype(終点)

それから以前に提示されたグラフィックはこれに拡張することができます(オリジナルのThief.prototypeは除外されます):

enter image description here

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

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

The Object-Oriented JavaScript Definitive Guide -質問の非常に簡潔で明確な〜30minのビデオの説明(プロトタイプ継承トピックは 5:45 から始まりますが、むしろビデオ全体を聞いてください)。このビデオの作成者は、JavaScriptオブジェクトビジュアライザーのWebサイトも作成しました http://www.objectplayground.com/ . enter image description hereenter image description here

16
Bad

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オブジェクトのプロパティによるそれらの関係のグラフをここで見つけることができます:

js objects graph

http://jsobjects.org

14
B M

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

13
Tom

説明が必要な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の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 のプロパティは次のように処理されます。

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

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

10
Aravind

次の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個のインスタンスそれぞれに対してまったく同じことを実行しますが、すべてのインスタンスに独自のこの関数のコピーがあります。

さて、getsetdelete、および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つのメソッドを共有しているということです。

9
John Slegers

JavaScriptプロトタイプベースの継承 /より良い写真付きで説明するもう1つの試み

Simple objects inheritanse

8
rus1

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

想像してみてください。

あなたは高校生です、そして、あなたはクラスにいて、そして今日予定されているクイズを持っています、しかしあなたはあなたの答えを記入するペンを持っていません。やあ!

あなたはペンを持っているかもしれないあなたの友人Finniusの隣に座っています。あなたが尋ねると、彼は机の周りを見回して失敗しましたが、「私はペンを持っていません」と言う代わりに、彼はもう一方の友人Derpと彼がペンを持っているか調べます。 Derpは確かに予備のペンを持っていて、それをFinniusに渡し、Finniusはあなたにそれを渡してクイズを完成させます。 DerpはそのペンをFinniusに任せました。

ここで重要なことは、あなたが彼と直接の 関係 を持っていないので、Derpはあなたにペンを渡さないことです。

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

7
Louis Moore

概要:

  • 関数は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);

4

__proto__ prototype および コンストラクタ を示す別のスキーム: enter image description here

3
IvanM

それは、あなたが既にObject.newを持つオブジェクトを持っているということですが、コンストラクタ構文を使うとき、あなたはまだオブジェクトを持っていません。

2
shiva kumar

プロトタイプ 新しいオブジェクトを作成する 既存の オブジェクトを複製することによって 。つまり、プロトタイプについて考えるときには、 クローン作成または作成 それを作成するのではなく、コピーを作成することができます。

2
Arif

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

参照: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes

0
Baraa Al-Tabbaa