JavaScriptでのOOPの理解[パヌト1]

-プロトタむプの継承は玠晎らしい

JavaScriptは、倖芳はJavaのように芋えたすが、 Self蚀語に根ざしたオブゞェクト指向OO蚀語です。 この事実は、いく぀かの玠晎らしい機胜のおかげで蚀語を本圓に匷力にしたす。



これらの機胜の1぀は、プロトタむプ継承の実装です。 このシンプルなコンセプトは柔軟で匷力です。 関数が関数型蚀語JavaScriptを含むの最初のクラスのオブゞェクトであるように、最初のクラスの継承および動䜜゚ンティティを䜜成できたす。



幞いなこずに、 ECMAScript 5には倚くのこずが登堎し、蚀語を正しい道に眮くこずができたしたその䞀郚はこの蚘事で開瀺されおいたす。 たた、JavaScriptデザむンの欠陥に぀いお説明し、埓来のプロトタむプOOモデル長所ず短所を含むず少し比范したす。



この蚘事では、読者がJavaScriptの基本にすでに粟通しおおり、関数クロヌゞャヌずファヌストクラス関数の抂念を含む、プリミティブ倀、挔算子などを理解しおいるこずを前提ずしおいたす。



1.オブゞェクト



JavaScriptのオブゞェクトは、キヌず倀のペアのコレクションにすぎたせん堎合によっおはちょっずした内郚の魔法もありたす。



ただし、JavaScriptにはクラスの抂念はありたせん。 たずえば、プロパティ{nameLinda、age21}を持぀オブゞェクトは、クラスたたはクラスObjectのむンスタンスではありたせん。 ObjectずLindaはどちらも自身のむンスタンスです。 圌らは圌ら自身の行動によっお盎接決定されたす。 これらのオブゞェクトに動䜜を指瀺するメタデヌタレむダヌクラスなどはありたせん。



「どうですか」ず尋ねるこずができたす。特に、叀兞的なオブゞェクト指向蚀語JavaやCなどの䞖界から来た堎合はそうです。 「しかし、各オブゞェクトが共通のクラスから継承するのではなく独自の動䜜を持぀堎合、100個のオブゞェクトがある堎合、100個の異なるメ゜ッドがそれらに察応したすか 危険ではありたせんか そしお、䟋えば、オブゞェクトが本圓に配列であるこずをどうやっお知るのですか」



これらのすべおの質問に答えるには、埓来のオブゞェクト指向アプロヌチを忘れお、れロから始める必芁がありたす。 私を信じお、それは䟡倀がある。



プロトタむプOOモデルは、叀い問題を解決するためのいく぀かの新しい動的で衚珟力豊かな方法をもたらしたす。 たた、コヌドを拡匵および再利甚するための匷力なモデルも提䟛したすこれは、オブゞェクト指向プログラミングに぀いお話す人々にずっお興味深いものです。 ただし、このモデルでは保蚌が少なくなりたす。 たずえば、オブゞェクトxに䟝存しお、垞に同じプロパティセットを保持するこずはできたせん。



1.1。 そしお、オブゞェクトずは䜕ですか


オブゞェクトは、察応する倀を持぀䞀意のキヌの単玔なペアであるこずが先に述べられたした-そのようなペアはプロパティず呌ばれたす。 たずえば、幎霢、名前、性別など、叀い友人のいく぀かの偎面ミシャ、別名ミハむルず呌びたしょうを説明したす。



JavaScriptのオブゞェクトは、 Object.create関数を䜿甚しお䜜成されたす。 この関数は、芪ずオプションのプロパティセットから新しい゚ンティティを䜜成したす。 今のずころ、パラメヌタに぀いおは心配したせん。



空のオブゞェクトは、芪ずプロパティのないオブゞェクトです。 JavaScriptでそのようなオブゞェクトを䜜成するための構文を芋おみたしょう。

var mikhail = Object.create(null)
      
      







1.2。 プロパティ䜜成


぀たり、オブゞェクトはすでにあるが、ただプロパティはないずいうこずです。この状況を修正しお、 ミハむルオブゞェクトを蚘述する必芁がありたす。



JavaScriptプロパティは動的です。 これは、い぀でも䜜成たたは削陀できるこずを意味したす。 プロパティは、オブゞェクト内のプロパティキヌが正確に1぀の倀に察応するずいう意味で䞀意です。



Object.defineProperty関数を䜿甚しお新しいプロパティを䜜成したす。この関数は、オブゞェクトを匕数ずしお䜿甚し、䜜成するプロパティの名前、およびプロパティのセマンティクスを説明するハンドルを䜿甚したす。

 Object.defineProperty(mikhail, 'name', { value: 'Mikhail' , writable: true , configurable: true , enumerable: true }) Object.defineProperty(mikhail, 'age', { value: 19 , writable: true , configurable: true , enumerable: true }) Object.defineProperty(mikhail, 'gender', { value: 'Male' , writable: true , configurable: true , enumerable: true })
      
      





指定されたキヌを持぀プロパティが以前に存圚しなかった堎合、 Object.defineProperty関数は新しいプロパティを䜜成したすそうでなければ、既存のプロパティのセマンティクスず倀が曎新されたす。



ずころで、オブゞェクトに耇数のプロパティを远加する必芁がある堎合は、 Object.definePropertiesを䜿甚するこずもできたす。

 Object.defineProperties(mikhail, { name: { value: 'Mikhail' , writable: true , configurable: true , enumerable: true } , age: { value: 19 , writable: true , configurable: true , enumerable: true } , gender: { value: 'Male' , writable: true , configurable: true , enumerable: true }})
      
      





明らかに、䞡方の呌び出しは類䌌しおおり、完党に構成可胜ですが、コヌドの゚ンドナヌザヌ向けではありたせん。 それらの䞊に抜象化レむダヌを䜜成するこずをお勧めしたす。



1.3。 蚘述子


セマンティクスを含む小さなオブゞェクトは蚘述子ず呌ばれたす Object.definePropertyを呌び出すずきに䜿甚したした。 蚘述子は、デヌタ蚘述子ずアクセス蚘述子の2぀のタむプのいずれかです。



䞡方のタむプの蚘述子には、蚀語によるプロパティの考慮方法を決定するフラグが含たれおいたす。 フラグが蚭定されおいない堎合、そのデフォルト倀はfalseです 残念ながら、これは垞に適切なデフォルト倀ではないため、蚘述子の蚘述量が増加したす。



いく぀かのフラグを怜蚎しおください。





アクセス蚘述子は、関数のゲッタヌずセッタヌを介しお特定の倀ぞのアクセスを定矩したす。 蚭定されおいない堎合、デフォルトはundefinedです。



プロパティの倀を倉曎したす。



1.4。 簡朔さを目指しお


幞いなこずに、プロパティ蚘述子はJavaScriptでプロパティを操䜜する唯䞀の方法ではありたせん-より簡朔に䜜成できたす。



JavaScriptは、括匧ず呌ばれるものを䜿甚しおプロパティ参照も理解したす。 基本的なルヌルは次のように曞かれおいたす。

 <bracket-access> ::= <identifier> "[" <expression> "]"
      
      





ここでidentifierは、倀を蚭定するプロパティを含むオブゞェクトを栌玍する倉数であり、 expressionはプロパティの名前を定矩する有効なJavaScript匏です。 プロパティが持぀こずができる名前に制限はありたせん;すべおが蚱可されおいたす。



したがっお、前の䟋を曞き換えるこずができたす。

 mikhail['name'] = 'Mikhail' mikhail['age'] = 19 mikhail['gender'] = 'Male'
      
      





泚すべおのプロパティ名は最終的に文字列に倉換されたす。 ゚ントリobject [1] 、 object [[1]] 、 object ['1']およびobject [variable]  variableの倀は1は同等です。



ポむントキャプチャず呌ばれるプロパティにアクセスする別の方法がありたす。 ブラケットの代替よりもシンプルで簡朔に芋えたす。 ただし、このメ゜ッドでは、プロパティの名前は有効なJavaScript識別子のルヌルに準拠する必芁があり、匏で衚すこずはできたせん぀たり、倉数は䜿甚できたせん。



スポット蚘録の䞀般的なルヌル

 <dot-access> ::= <identifier> "." <identifier-name>
      
      





したがっお、前の䟋はさらに矎しくなりたした。

 mikhail.name = 'Mikhail' mikhail.age = 19 mikhail.gender = 'Male'
      
      





䞡方の構文オプションは、セマンティックフラグをtrueに蚭定しお、プロパティを䜜成する同等のプロセスを実行したす 。



1.5。 プロパティぞのアクセス


特定のプロパティに栌玍された倀を取埗するのは非垞に簡単です-構文は、プロパティを䜜成するのに非垞に䌌おいたすが、割り圓おがないずいう唯䞀の違いがありたす。

たずえば、ミヌシャの幎霢を知りたい堎合は、次のように蚘述したす。

 mikhail['age'] // => 19
      
      





しかし、オブゞェクトに存圚しないプロパティの倀を取埗しようずするず、 未定矩になりたす

 mikhail['address'] // => undefined
      
      







1.6。 プロパティの削陀


オブゞェクトからプロパティを削陀するために、JavaSCriptには削陀挔算子が甚意されおいたす。 たずえば、 mikhailオブゞェクトからgenderプロパティを削陀する堎合

 delete mikhail['gender'] // => true mikhail['gender'] // => undefined
      
      





削陀挔算子は、プロパティが削陀された堎合はtrueを返し、 そうでない堎合はfalseを返したす 。 この挔算子の仕組みに぀いおは詳しく説明したせん。 しかし、ただ興味がある堎合は、 削陀の仕組みに関する最も優れた蚘事を読むこずができたす。



1.6。 ゲッタヌずセッタヌ


ゲッタヌずセッタヌは、カプセル化を提䟛するために叀兞的なオブゞェクト指向蚀語で䞀般的に䜿甚されたす。 JavaScriptでは特に必芁ありたせんが、動的蚀語があるため、 この機胜には反察です 。



ただし、あらゆる芳点から、プロパティの読み取りおよび曞き蟌み芁求のプロキシを提䟛したす。 たずえば、姓ず名に別々のスロットがありたしたが、それらを読んでむンストヌルする䟿利な方法が必芁です。



最初に、適切なプロパティを蚘述しお、友人の名前ず姓を䜜成したす。

 Object.defineProperty(mikhail, 'first_name', { value: 'Mikhail' , writable: true }) Object.defineProperty(mikhail, 'last_name', { value: 'Weiß' , writable: true })
      
      





次に、䞀床に2぀のプロパティを䞀床に取埗および蚭定する䞀般的な方法に぀いお説明したす。ナニオン名を呌び出したしょう。

 // () → String // Returns the full name of object. function get_full_name() { return this.first_name + ' ' + this.last_name } // (new_name:String) → undefined // Sets the name components of the object, from a full name. function set_full_name(new_name) { var names names = new_name.trim().split(/\s+/) this.first_name = names[⁣'0'] || '' this.last_name = names['1'] || '' } Object.defineProperty(mikhail, 'name', { get: get_full_name , set: set_full_name , configurable: true , enumerable: true })
      
      





さお、友人のnameプロパティの倀を芋぀けようずするたびに、get_full_name関数が実際に呌び出されたす

 mikhail.name // => 'Mikhail Weiß' mikhail.first_name // => 'Mikhail' mikhail.last_name // => 'Weiß' mikhail.last_name = 'White' mikhail.name // => 'Mikhail White'
      
      





察応するプロパティにアクセスするこずでオブゞェクトの名前を蚭定するこずもできたすが、実際にset_full_nameを呌び出すず、すべおの汚れた䜜業が行われたす。

 mikhail.name = 'Michael White' mikhail.name // => 'Michael White' mikhail.first_name // => 'Michael' mikhail.last_name // => 'White'
      
      





そうするのが本圓に䟿利なシナリオもありたすが、そのようなメカニズムの動䜜は非垞に遅いこずを芚えおおく䟡倀がありたす。

さらに、ゲッタヌずセッタヌは通垞、カプセル化のために他の蚀語で䜿甚され、ECMAScript 5ではこれを実行できないこずに留意しおください。すべおのオブゞェクトプロパティはパブリックです。



1.8。 物件リスト


プロパティは動的であるずいう事実により、JavaScriptはオブゞェクトのプロパティのセットをチェックする機胜を提䟛したす。 興味のあるプロパティの皮類に応じお、オブゞェクトのすべおのプロパティをリストする2぀の方法がありたす。



最初の方法はObject.getOwnPropertyNames関数を呌び出すこずです。この関数は、このオブゞェクトに蚭定されたすべおのプロパティの名前を含む配列を返したす。これらのプロパティを独自のものず呌びたす。 たずえば、Mishaに぀いお知っおいるこずを芋おみたしょう。

 Object.getOwnPropertyNames(mikhail) // => [ 'name', 'age', 'gender', 'first_name', 'last_name' ]
      
      





2番目の方法は、 列挙可胜なフラグでマヌクされた独自のプロパティのリストを返すObject.keysを䜿甚するこずです 。

 Object.keys(mikhail) // => [ 'name', 'age', 'gender' ]
      
      







1.9。 リテラル


オブゞェクトを䜜成する簡単な方法は、リテラルJavaScript構文を䜿甚するこずです。 リテラルオブゞェクトは、芪がObject.prototypeである新しいオブゞェクトを定矩したす芪に぀いおは埌で説明したす。



いずれの堎合でも、リテラルオブゞェクトの構文を䜿甚するず、単玔なオブゞェクトを定矩しおそのプロパティを初期化できたす。 Mikhailオブゞェクトを䜜成する䟋を曞き換えたす

 var mikhail = { first_name: 'Mikhail' , last_name: 'Weiß' , age: 19 , gender: 'Male' // () → String // Returns the full name of object. , get name() { return this.first_name + ' ' + this.last_name } // (new_name:String) → undefined // Sets the name components of the object, // from a full name. , set name(new_name) { var names names = new_name.trim().split(/\s+/) this.first_name = names['0'] || '' this.last_name = names['1'] || '' } }
      
      







無効なプロパティ名は匕甚笊で囲むこずができたす。 リテラル圢匏のゲッタヌ/セッタヌの゚ントリは、匿名関数によっお決定されるこずに泚意しおください。 以前に宣蚀した関数をゲッタヌ/セッタヌに関連付ける堎合は、 Object.definePropertyメ゜ッドを䜿甚する必芁がありたす。



リテラル構文の䞀般的なルヌルを芋おみたしょう。

 <object-literal> ::= "{" <property-list> "}" ; <property-list> ::= <property> ["," <property>]* ; <property> ::= <data-property> | <getter-property> | <setter-property> ; <data-property> ::= <property-name> ":" <expression> ; <getter-property> ::= "get" <identifier> : <function-parameters> : <function-block> ; <setter-property> ::= "set" <identifier> : <function-parameters> : <function-block> ; <property-name> ::= <identifier> | <quoted-identifier> ;
      
      





リテラルオブゞェクトは、JavaScriptの匏内に衚瀺できたす。 いく぀かのあいたいさのために、初心者は時々混乱したす

 // This is a block statement, with a label: { foo: 'bar' } // => 'bar' // This is a syntax error (labels can't be quoted): { "foo": 'bar' } // => SyntaxError: Invalid label // This is an object literal (note the parenthesis to force // parsing the contents as an expression): ({ "foo": 'bar' }) // => { foo: 'bar' } // Where the parser is already expecting expressions, // object literals don't need to be forced. Eg: var x = { foo: 'bar' } fn({foo: 'bar'}) return { foo: 'bar' } 1, { foo:
      
      







2.メ゜ッド



これたでのずころ、 Mikhailオブゞェクトにはデヌタを保存するためのスロットしかありたせん nameプロパティのgetter / setterを陀く。 オブゞェクトで実行できるアクションの蚘述は、JavaScriptで非垞に簡単に行われたす。 シンプル-JavaScriptでは、 Function 、 Number 、 Objectなどの操䜜に違いがないためです。 すべおが同じ方法で行われたすJavaScriptの関数が䞀流の゚ンティティであるこずを忘れないでください。



関数をプロパティの倀ずしお蚭定するだけで、このオブゞェクトに察するアクションを蚘述したす。 たずえば、ミヌシャに他の人を歓迎しおもらいたい

 // (person:String) → String // Greets a random person mikhail.greet = function(person) { return this.name + ': Why, hello there, ' + person + '.' }
      
      





プロパティ倀を蚭定したら、同様の方法を䜿甚しお、オブゞェクトに関連付けられた特定のデヌタを蚭定できたす。 したがっお、プロパティにアクセスするず、プロパティに保存されおいる関数ぞのリンクが返されたす。

 mikhail.greet('you') // => 'Michael White: Why, hello there, you.' mikhail.greet('Kristin') // => 'Michael White: Why, hello there, Kristin.'
      
      







2.1。 ダむナミックこれ


greet関数を蚘述するずきに留意すべきこずの1぀は、この関数はnameプロパティのgetter / setterにアクセスする必芁があり、このためにthisマゞック倉数を䜿甚するこずです。



実行䞭の関数が属するオブゞェクトぞの参照を保存したす。 これは、必ずしもこれが関数が栌玍されおいるオブゞェクトず垞に等しいこずを意味するわけではありたせん。 いいえ、JavaScriptはそれほど利己的ではありたせん。



関数は汎甚です。 ぀たり JavaScriptでは、 this倉数は、関数の実行時に解決されるダむナミックリンクを定矩したす。



これにより、JavaScriptオブゞェクトの向きを動的に倉曎するための非垞に匷力なメカニズムが提䟛される動的な解決プロセスが提䟛され、特定の構造クラスなどぞの厳密な準拠の欠劂が補われたす。 これは、オブゞェクトの配眮方法に関係なく、起動の芁件を満たすオブゞェクトに関数を適甚できるこずを意味したす CLOSなど 。



2.2。 この蚱可


関数の呌び出し方法に応じお、関数でこれを有効にする4぀の異なる方法がありたす。メ゜ッドずしお盎接、コンストラクタヌずしお明瀺的に適甚されたす。 最初の3぀を確認し、埌でデザむナヌに戻りたす。



次の䟋では、次のものを取りたす。

 // Returns the sum of the object's value with the given Number function add(other, yet_another) { return this.value + other + (yet_another || 0) } var one = { value: 1, add: add } var two = { value: 2, add: add }
      
      







2.2.1メ゜ッドずしおの呌び出し


関数がオブゞェクトメ゜ッドずしお呌び出される堎合、関数内のこれはオブゞェクト自䜓を参照したす。 ぀たり どのオブゞェクトがアクションを実行するかを明瀺的に瀺すず、オブゞェクトは関数のthisの倀になりたす。



これは、 mikhail.greetを呌び出すずきに発生したす。 この゚ントリは、 mikhailオブゞェクトにあいさ぀アクションを適甚するこずをJavaScriptに䌝えたす。

 one.add(two.value) // this === one // => 3 two.add(3) // this === two // => 5 one['add'](two.value) // brackets are cool too // => 3
      
      







2.2.2盎接呌び出し


関数が盎接呌び出されるず、 これぱンゞンのグロヌバルオブゞェクトブラりザヌのりィンドり 、Node.jsのグロヌバル に解決されたす。

 add(two.value) // this === global // => NaN // The global object still has no `value' property, let's fix that. value = 2 add(two.value) // this === global // => 4
      
      







2.2.3。 明瀺的な適甚


結論ずしお、オブゞェクトに察応するプロパティがあるかどうかに関係なく、関数は任意のオブゞェクトに明瀺的に適甚できたす。 この機胜は、 callメ゜ッドたたはapplyメ゜ッドを䜿甚しお実珟されたす。



2぀のメ゜ッドの違いは、関数に枡されるパラメヌタヌず実行時間です。applyは盎接呌び出しよりも玄55倍遅くなりたすが 、通垞、 呌び出しはそれほど悪くありたせん。 すべおは珟圚の゚ンゞンに䟝存するため、 Perfテストを䜿甚しお確認しおください。事前にコヌドを最適化しないでください。



いずれの堎合でも、 callは関数の最初のパラメヌタヌずしおオブゞェクトを期埅し、その埌に元の関数ぞの通垞の匕数が続きたす。

 add.call(two, 2, 2) // this === two // => 6 add.call(window, 4) // this === global // => 6 add.call(one, one.value) // this === one // => 2
      
      





䞀方、 applyでは、元の関数のパラメヌタヌの配列を2番目のパラメヌタヌずしお蚘述するこずができたす。

 add.apply(two, [2, 2]) // equivalent to two.add(2, 2) // => 6 add.apply(window, [ 4 ]) // equivalent to add(4) // => 6 add.apply(one, [one.value]) // equivalent to one.add(one.value) // => 2
      
      





メモぞ。 nullたたはundefinedの この蚱可は、䜿甚する゚ンゞンのセマンティクスに䟝存するこずに泚意しおください。 通垞、結果は、関数をグロヌバルオブゞェクトに適甚した堎合ず同じです。 しかし、゚ンゞンがストリクトモヌドで動䜜する堎合、 これは期埅どおりに解決されたす-たさにそれが適甚されるもの

 window.value = 2 add.call(undefined, 1) // this === window // => 3 void function() { "use strict" add.call(undefined, 1) // this === undefined // => NaN // Since primitives can't hold properties. }()
      
      







2.3。 メ゜ッドバむンディング


JavaScriptの関数の動的な性質から泚意をそらしたしょう。関数を特定のオブゞェクトに関連付けるこずにより、関数を䜜成するパスをたどりたす。そのため、関数内でこれは、オブゞェクトメ゜ッドずしお、たたは盎接呌び出される方法に関係なく、垞に特定のオブゞェクトを指したす。



この関数はbindずいう機胜を提䟛したす。オブゞェクトず远加のパラメヌタヌ callの呌び出しに非垞に䌌おいたす を受け取り、呌び出されたずきに元の関数にパラメヌタヌを適甚する新しい関数を返したす。

 var one_add = add.bind(one) one_add(2) // this === one // => 3 two.one_adder = one_add two.one_adder(2) // this === one // => 3 one_add.call(two) // this === one // => 3
      
      







3.継承



これたで、オブゞェクトがどのように動䜜を決定し、他のオブゞェクトでどのようにアクションを䜿甚できるかを芋おきたしたが、これたで、コヌドの再利甚ずその拡匵性の通垞の方法は芋おいたせん。



これは、継承が圹立぀堎所です。 これにより、オブゞェクトが特殊な動䜜を定矩するタスクを、他のオブゞェクトの共通の動䜜を䜜成するこずから分離できたす。



プロトタむピングモデルはさらに進んでいたす。 「遞択的拡匵性」や「ビヘむビアシェアリング」などのテクノロゞヌをサポヌトしおいたすが、それらに぀いおは特に怜蚎したせん。 悲しいこずに、JavaScriptで実装されおいる特定のプロトタむプOOモデルはやや制限されおいたす。 これらの制限を回避できたすが、オヌバヌヘッドは倧きくなりたす。



3.1。 プロトタむプ


JavaScriptの継承は、オブゞェクトの動䜜を耇補し、特殊な動䜜で拡匵するこずで実珟されたす。 動䜜が耇補されるオブゞェクトは、 プロトタむプず呌ばれたす。



プロトタむプは、他のオブゞェクトず動䜜を共有する通垞のオブゞェクトです。この堎合、芪ずしお機胜したす。



クロヌン䜜成動䜜の抂念は、同じ関数たたはデヌタの2぀の異なるコピヌがあるこずを意味したせん。 実際、JavaScriptは委任を介しお継承を実装しおいたす。 すべおのプロパティは芪に保存され、それらぞのアクセスは子を通じお拡匵されたす。



前述のように、オブゞェクトの芪たたは[[Prototype]] は、芪オブゞェクトを参照する最初の匕数でObject.createを呌び出すこずにより定矩されたす。



Mishaの䟋に戻りたしょう。 圌の名前ず、圌の行動をミシャず共有する別のオブゞェクトで人々に挚拶する胜力を特定したす。 モデルは次のようになりたす。



JavaScriptで実装したす。

 var person = Object.create(null) // Here we are reusing the previous getter/setter functions Object.defineProperty(person, 'name', { get: get_full_name , set: set_full_name , configurable: true , enumerable: true }) // And adding the `greet' function person.greet = function (person) { return this.name + ': Why, hello there, ' + person + '.' } // Then we can share those behaviours with Mikhail // By creating a new object that has it's [[Prototype]] property // pointing to `person'. var mikhail = Object.create(person) mikhail.first_name = 'Mikhail' mikhail.last_name = 'Weiß' mikhail.age = 19 mikhail.gender = 'Male' // And we can test whether things are actually working. // First, `name' should be looked on `person' mikhail.name // => 'Mikhail Weiß' // Setting `name' should trigger the setter mikhail.name = 'Michael White' // Such that `first_name' and `last_name' now reflect the // previously name setting. mikhail.first_name // => 'Michael' mikhail.last_name // => 'White' // `greet' is also inherited from `person'. mikhail.greet('you') // => 'Michael White: Why, hello there, you.' // And just to be sure, we can check which properties actually // belong to `mikhail' Object.keys(mikhail) // => [ 'first_name', 'last_name', 'age', 'gender' ]
      
      







3.2しかし、 [⁣[プロトタむプ]⁣]はどのように機胜したすか


前の䟋で芋たように、 Mikhailの Personで定矩されおいるプロパティは明瀺的に定矩しおいたせんが、それらにアクセスするこずはできたした。 これは、JavaScriptがプロパティぞのアクセスの委任を実装しおいるずいう事実、぀たり プロパティは、オブゞェクトのすべおの芪を通しお怜玢されたす。



この芪のチェヌンは、各オブゞェクトの[⁣[プロトタむプ]⁣]ず呌ばれる隠しスロットによっお定矩されたす。 盎接倉曎するこずはできたせん。倀を蚭定する方法は1぀しかありたせん-新しいオブゞェクトを䜜成するずきです。



オブゞェクトからプロパティが芁求されるず、゚ンゞンは最初にタヌゲットからプロパティを取埗しようずしたす。 プロパティが芋぀からない堎合、オブゞェクトの盎接の芪、次に芪の芪などが考慮されたす。



これは、プログラムの途䞭でプロトタむプの動䜜を倉曎でき、それから継承されたすべおのオブゞェクトの動䜜が自動的に倉曎されるこずを意味したす。 たずえば、デフォルトの挚拶を倉曎するずしたす。

 // (person:String) → String // Greets the given person person.greet = function(person) { return this.name + ': Harro, ' + person + '.' } mikhail.greet('you') // => 'Michael White: Harro, you.'
      
      







3.3。 プロパティのオヌバヌロヌド


そのため、プロトタむピング぀たり、継承を䜿甚しお、他のオブゞェクトずデヌタを共有できたす。 さらに、この方法はメモリに関しお迅速か぀経枈的に機胜したす。 䜿甚されるデヌタのむンスタンスは垞に1぀だけです。



, ? , — .



, Person , Person . , :





, mikhail , kristin greet . greet , greet , Person :

 // Here we set up the greeting for a generic person // (person:String) → String // Greets the given person, formally person.greet = function(person) { return this.name + ': Hello, ' + (person || 'you') } // And a greeting for our protagonist, Mikhail // (person:String) → String // Greets the given person, like a bro mikhail.greet = function(person) { return this.name + ': \'sup, ' + (person || 'dude') } // And define our new protagonist, Kristin var kristin = Object.create(person) kristin.first_name = 'Kristin' kristin.last_name = 'Weiß' kristin.age = 19 kristin.gender = 'Female' // Alongside with her specific greeting manners // (person:String) → String // Greets the given person, sweetly kristin.greet = function(person) { return this.name + ': \'ello, ' + (person || 'sweetie') } // Finally, we test if everything works according to the expected mikhail.greet(kristin.first_name) // => 'Michael White: \'sup, Kristin' mikhail.greet() // => 'Michael White: \'sup, dude' kristin.greet(mikhail.first_name) // => 'Kristin Weiß: \'ello, Michael' // And just so we check how cool this [[Prototype]] thing is, // let's get Kristin back to the generic behaviour delete kristin.greet // => true kristin.greet(mikhail.first_name) // => 'Kristin Weiß: Hello, Michael'
      
      







続行するには...



All Articles