diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/ja/learn/javascript/objects | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/ja/learn/javascript/objects')
9 files changed, 2342 insertions, 0 deletions
diff --git a/files/ja/learn/javascript/objects/adding_bouncing_balls_features/index.html b/files/ja/learn/javascript/objects/adding_bouncing_balls_features/index.html new file mode 100644 index 0000000000..8390797c5b --- /dev/null +++ b/files/ja/learn/javascript/objects/adding_bouncing_balls_features/index.html @@ -0,0 +1,223 @@ +--- +title: バウンスボールに機能を追加する +slug: Learn/JavaScript/Objects/Adding_bouncing_balls_features +tags: + - Assessment + - Beginner + - CodingScripting + - JavaScript + - Learn + - OOJS + - Object-Oriented + - Objects + - 'l10n:priority' +translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">この評価では、前の記事のバウンスボールのデモを出発点として用い、いくつかの面白い機能を新たに追加してもらいます。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>この評価を試みる前に、このモジュールのすべての記事を学習済みであること。</td> + </tr> + <tr> + <th scope="row"> + <p>目的:</p> + </th> + <td>JavaScript オブジェクトとオブジェクト指向のインスタンス生成を理解しているかテストする。</td> + </tr> + </tbody> +</table> + +<h2 id="Starting_point" name="Starting_point">出発点</h2> + +<p>この評価をスタートするためには、私たちの最新記事からローカル PC の新しいディレクトリーに<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/index-finished.html"> index-finished.htm</a>、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/style.css">style.css</a>、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main-finished.js">main-finshed.js</a> をコピーします。</p> + +<p>または、あなたの評価のために、<a class="external external-icon" href="http://jsbin.com/">JSBin</a> や <a class="external external-icon" href="https://glitch.com/">Glitch</a> を使うことができます。これらのオンラインエディターに HTML、CSS や JavaScript を貼り付けることができます。もしあなたが使用しているオンラインエディタが、別々の JavaScript/CSS のパネルを持っていない場合は、HTML内の <code><script></code>/<code><style></code> 要素を使って、インラインで書くことができます。</p> + +<div class="note"> +<p><strong>注</strong>: もし行き詰った場合は、サポートを依頼してください。このページの下部にある{{anch("Assessment or further help", "評価とさらなる支援")}}セクションを参照してください。</p> +</div> + +<h2 id="Hints_and_tips" name="Hints_and_tips">ヒントと tips</h2> + +<p>始める前にいくつかの助言です。</p> + +<ul> + <li>この評価はかなり難しいです。コーディングを始める前に評価全体を読み、各ステップをゆっくりと注意深く行ってください。</li> + <li>それぞれのステージを作業した後のデモを、別々のコピーとして保管しておけば、後で困ったときに参照することができます。</li> +</ul> + +<h2 id="Project_brief" name="Project_brief">プロジェクト概要</h2> + +<p>このバウンスボールのデモは面白いですが、ここではもう少しインタラクティブにするため、バウンスボールを捕まえたら食べてしまう、ユーザー制御された邪悪な円を追加します。また、<span style='background-color: transparent; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;'>バウンスボールや</span>邪悪な<span style='background-color: transparent; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;'>円が継承できる</span>一般的な <code>Shape()</code> オブジェクトを作ることで、<span style='background-color: transparent; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;'>あなたのオブジェクト構築スキルも</span>試してみましょう。最後に、残ったボールが数えられるスコアカウンターも追加してみましょう。</p> + +<p>次のスクリーンショットでは、完成したプログラムがどのように見えるかのイメージを掴めるでしょう: </p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13875/bouncing-evil-circle.png" style="display: block; margin: 0 auto;"></p> + +<ul> +</ul> + +<p>さらにヒントを差し上げます。<a href="http://mdn.github.io/learning-area/javascript/oojs/assessment/">完成デモ</a>を見てみましょう。(ソースコードをチラ見しないように!)</p> + +<h2 id="Steps_to_complete" name="Steps_to_complete">完成までの手順</h2> + +<p>次のセクションでは、必要な操作について説明します。</p> + +<h3 id="Creating_our_new_objects" name="Creating_our_new_objects">新しいオブジェクトを作る</h3> + +<p>まず初めに、既存の <code>Ball()</code> コンストラクターを <code>Shape()</code> コンストラクターに変更し、新しい <code>Ball()</code> コンストラクターを追加します:</p> + +<ol> + <li><code>Shape()</code> コンストラクターは、<code>x</code>、<code>y</code>、<code>velX</code>、および、<code>velY</code> プロパティを、<code>Ball()</code> コンストラクターが最初に行ったのと同じ方法で定義する必要がありますが、色とサイズのプロパティは指定しません。</li> + <li>また、新しいプロパティとして、ボールが存在するか(邪悪な円に食べられていないか)どうかを追跡するために使用される <code>exists</code> を新しく定義する必要があります。これはブール値 (<code>true</code>/<code>false</code>) である必要があります。</li> + <li><code>Ball()</code> コンストラクターは、<code>x</code>、<code>y</code>、<code>velX</code>、<code>velY</code>、および <code>exists</code> プロパティを <code>Shape()</code> コンストラクターから継承する必要があります。</li> + <li>また、元の <code>Ball()</code> コンストラクターのように、<code>color</code> と <code>size</code> プロパティを定義する必要があります。</li> + <li><code>Ball()</code> コンストラクターの <code>prototype</code> と <code>constructor</code> を適切に設定してください。</li> +</ol> + +<p>ボールの <code>draw()</code>、<code>update()</code>、と <code>collisionDetect()</code> メソッドの定義は、前とまったく同じである必要があります。</p> + +<p>また、<code>new Ball() ( ... )</code> <span style='background-color: transparent; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;'>コンストラクターの呼び出し</span>に新しいパラメーターを追加する必要があります。<code>exists</code> パラメーターは 5番目のパラメーターにする必要があり、<code>true</code> の値を指定する必要があります。</p> + +<p>この時点で、コードをリロードしてみてください。再設計されたオブジェクトで、前と全く同じように動作するはずです。</p> + +<h3 id="Defining_EvilCircle" name="Defining_EvilCircle">EvilCircle() の定義</h3> + +<p>さあ、悪者 <code>EvilCircle()</code> の出番です! 私たちのゲームに邪悪な円は1つしか登場しませんが、練習のためにあえて、<code>Shape()</code> から継承するコンストラクターを使用して定義します。後で、他のプレイヤーによって制御される円、あるいは、コンピューター制御の別の邪悪な円をいくつか加えたいと思うかもしれません。おそらく、あなたは単一の邪悪な円の世界を引き継いでいくつもりはないでしょうが、今回の評価のためにはこれで十分です。</p> + +<p><code>EvilCircle()</code> コンストラクターは、<code>x</code>, <code>y</code>, <code>velX</code>, <code>velY</code> と <code>exists</code> を <code>Shape()</code> から継承しますが、<code>velX</code> と <code>velY</code> は常に20です。</p> + +<p>これは <code>Shape.call(this, x, y, 20, 20, exists);</code>のように呼び出します。</p> + +<p>次のように、独自のプロパティも定義する必要があります:</p> + +<ul> + <li><code>color</code> — <code>'white'</code></li> + <li><code>size</code> — <code>10</code></li> +</ul> + +<p>ここでも、継承したプロパティをコンストラクターのパラメーターとして定義し、<code>prototype</code> と <code>constractor</code> のプロパティを正しく設定することを忘れないでください。</p> + +<h3 id="Defining_EvilCircles_methods" name="Defining_EvilCircles_methods">EvilCircle() のメソッドの定義</h3> + +<p><code>EvilCircle()</code> には、以下に示す 4 つのメソッドがあります。</p> + +<h4 id="draw" name="draw"><code>draw()</code></h4> + +<p>このメソッドは、<code>Ball()</code> の <code>draw()</code> メソッドと同じく、キャンバス上にオブジェクトインスタンスを描画するという目的を持ちます。とても良く似た動作をするので、<code>Ball.prototype.draw</code> の定義をコピーすることから始めます。次に、以下の変更を行います。</p> + +<ul> + <li>邪悪な円は塗りつぶしせず、枠線(ストローク)だけを持たせたいと思います。そのために、<code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/fillStyle">fillStyle</a></code> と <code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/fill">fill()</a></code> を <code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/strokeStyle">strokeStyle</a></code> と <code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/stroke">stroke()</a></code> に変更します。</li> + <li>また、線を少し太くすれば、邪悪な円が少し分かりやすくなります。これは、<code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/beginPath">beginPath()</a></code> 呼び出しの後のどこかで <code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/lineWidth">lineWidth</a></code> の値(3で十分でしょう)を設定することで実現できます 。</li> +</ul> + +<h4 id="checkBounds" name="checkBounds"><code>checkBounds()</code></h4> + +<p>このメソッドは、<code>Ball()</code>の <code>update()</code> 関数の最初の部分と同じ機能、すなわち、邪悪な円が画面の端から出そうになったら出ないようにする機能を持ちます。先ほどと同様に、<code>Ball.prototype.update</code> 定義をほぼコピーするだけでできますが、いくつか変更する必要があります。</p> + +<ul> + <li>最後の 2行を削除します。後で見られるように、別の方法で邪悪な円を動かすので、フレーム毎に邪悪な円の位置を自動的に更新する必要はありません。</li> + <li>テストが true を返す場合、<code>if()</code> ステートメントの内部で<code>velX</code>/<code>velY</code> を更新したくありません。代わりに <code>x</code>/<code>y</code> の値を変更して、邪悪な円が画面上に少し跳ね返ってくるようにします。邪悪な円の size プロパティを(必要に応じて)増減させることは理にかなっています。</li> +</ul> + +<h4 id="setControls" name="setControls"><code>setControls()</code></h4> + +<p>このメソッドは、<code>onkeydown</code> イベントリスナーを <code>window</code> オブジェクトに追加し、特定のキーボードキーが押されたときに、邪悪な円を動かします。次のコードブロックは、メソッド定義の中に置く必要があります。</p> + +<pre class="brush: js notranslate">let _this = this; +window.onkeydown = function(e) { + if (e.key === 'a') { + _this.x -= _this.velX; + } else if (e.key === 'd') { + _this.x += _this.velX; + } else if (e.key === 'w') { + _this.y -= _this.velY; + } else if (e.key === 's') { + _this.y += _this.velY; + } + }</pre> + +<p>キーが押されると、イベントオブジェクトの <a href="/ja/docs/Web/API/KeyboardEvent/key">key</a> プロパティを調べて、どのキーが押されているかを確認します。押されたキーが、指定された4つのキーの 1 つである場合、邪悪な円は左/右/上/下に移動します。</p> + +<p>おまけとして、<code>let _this = this;</code>をこの場所で設定しなければならない理由を教えてください。関数スコープと関係があります。</p> + +<h4 id="collisionDetect" name="collisionDetect"><code>collisionDetect()</code></h4> + +<p>このメソッドは <code>Ball()</code>の <code>collisionDetect()</code>メソッドと非常によく似た方法で動作するので、そのコピーをこの新しいメソッドの基礎として使用することができます。しかし、いくつかの違いがあります。</p> + +<ul> + <li>外側の <code>if</code> ステートメントでは、反復処理中のボールが、チェックを行っているボールと同じであるかをチェックする必要はなくなりました。なぜなら、それは邪悪な円であって、ボールではないからです! その代わりに、チェックされているボールが存在するかどうかを確認(どのプロパティでこれを行うことができるでしょうか?)するテストを行う必要があります。存在しなければ、それはすでに邪悪な円によって食べられているので、再度チェックする必要はありません。</li> + <li>内部の <code>if</code> ステートメントでは、衝突が検出されたときにオブジェクトの色を変更する必要がなくなりました。その代わりに、邪悪な円と衝突するボールをもう存在しないように設定します(どうやって実行すると思いますか?)。</li> +</ul> + +<h3 id="Bringing_the_evil_circle_into_the_program" name="Bringing_the_evil_circle_into_the_program">プログラムに邪悪な円を持ち込む</h3> + +<p>さて、邪悪な円を定義したので、実際にそれをシーンに表示させる必要があります。そのためには、<code>loop()</code> 関数をいくつか変更する必要があります。</p> + +<ul> + <li>まず、(必要なパラメーターを指定して)新しい邪悪な円オブジェクトインスタンスを作成し、その <code>setControls()</code> メソッドを呼び出します。これらの 2 つの処理は一度だけ実行すればよく、ループの繰り返し毎に行う必要はありません。</li> + <li>すべてのボールをループして、ボールが存在する場合にのみ、それぞれの <code>draw()</code>、<code>update()</code>、<code>collisionDetect()</code> が呼び出されるようにします。</li> + <li>ループの各繰り返しで、邪悪な円インスタンスの <code>draw()</code>、<code>checkBounds()</code>、および <code>collisionDetect()</code>メソッドを呼び出します。</li> +</ul> + +<h3 id="Implementing_the_score_counter" name="Implementing_the_score_counter">スコアカウンターの実装</h3> + +<p>スコアカウンターを実装するには、次の手順に従います。</p> + +<ol> + <li>HTML ファイルの{{HTMLElement("h1")}}要素の直下に、"Ball count:" というテキストを含む{{HTMLElement( "p")}}要素を追加します。</li> + <li>あなたの CSS ファイルに、次のスタイルを追加します: + <pre class="brush: css notranslate">p { + position: absolute; + margin: 0; + top: 35px; + right: 5px; + color: #aaa; +}</pre> + </li> + <li>JavaScript では、次の更新を行います: + <ul> + <li>段落への参照を格納する変数を作成します。</li> + <li>何らかの方法で画面上のボールの数をカウントしてください。</li> + <li>ボールをシーンに追加するたびにカウントを増加させ、更新されたボールの数を表示します。</li> + <li>邪悪な円がボールを食べる(存在を消す)たびにカウントを減らし、更新されたボールの数を表示します。</li> + </ul> + </li> +</ol> + +<h2 id="Assessment_or_further_help" name="Assessment_or_further_help">評価とさらなる支援</h2> + +<p>If you would like your work assessed, or are stuck and want to ask for help:</p> + +<ol> + <li>Put your work into an online shareable editor such as <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, or <a href="https://glitch.com/">Glitch</a>.</li> + <li>Write a post asking for assessment and/or help at the <a href="https://discourse.mozilla.org/c/mdn/learn">MDN Discourse forum Learning category</a>. Your post should include: + <ul> + <li>A descriptive title such as "Assessment wanted for Adding bouncing balls features".</li> + <li>Details of what you have already tried, and what you would like us to do, e.g. if you are stuck and need help, or want an assessment.</li> + <li>A link to the example you want assessed or need help with, in an online shareable editor (as mentioned in step 1 above). This is a good practice to get into — it's very hard to help someone with a coding problem if you can't see their code.</li> + <li>A link to the actual task or assessment page, so we can find the question you want help with.</li> + </ul> + </li> +</ol> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/basics/index.html b/files/ja/learn/javascript/objects/basics/index.html new file mode 100644 index 0000000000..0c97e391d3 --- /dev/null +++ b/files/ja/learn/javascript/objects/basics/index.html @@ -0,0 +1,277 @@ +--- +title: JavaScript オブジェクトの基本 +slug: Learn/JavaScript/Objects/Basics +tags: + - API + - Article + - Beginner + - CodingScripting + - JavaScript + - Syntax + - bracket notation + - dot notation + - instance + - object literal + - this + - オブジェクト + - 学習 + - 理論 +translation_of: Learn/JavaScript/Objects/Basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">この記事では、基本的な JavaScript オブジェクトの構文を学び、このコースで以前に見た一部の JavaScript の機能を復習し、すでに提供された多くの機能がオブジェクトであるという事実を再確認します。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提知識:</th> + <td>基本的なコンピューターを操作する能力、基本的な HTML と CSS に対する理解、基本的な JavaScript に親しんでいること(<a href="/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a>と <a href="/ja/docs/Learn/JavaScript/Building_blocks">JavaScript の構成要素</a>を参照してください)。</td> + </tr> + <tr> + <th scope="row">到達目標:</th> + <td>オブジェクト指向プログラミングについての基本的な理論、どのように JavaScript に関連するか、JavaScript の作業を始める方法を理解できること。</td> + </tr> + </tbody> +</table> + +<h2 id="Object_basics" name="Object_basics">オブジェクトの基本</h2> + +<p>オブジェクトとは関連のあるデータと機能の集合です。(機能はたいていは変数と関数で構成されており、オブジェクトの中ではそれぞれプロパティとメソッドと呼ばれます。) どんなものか例を見てみましょう。</p> + +<p>最初に <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> ファイルを手元にコピーしてください。このファイルにはちょっとした内容 — ソースコードを書き込むための {{HTMLElement("script")}} 要素が一つ含まれています。このファイルをオブジェクトを書くための元として使います。作業中は<a href="/ja/docs/Learn/Common_questions/What_are_browser_developer_tools#The_JavaScript_console">開発者ツールの JavaScript コンソール</a>を開いておいて、すぐにコマンドを入力できるようにしておくとよいでしょう。</p> + +<p>他の JavaScript の書き方と同じように、オブジェクトの生成は変数の宣言と初期化から始まります。手始めに、ファイルにある JavaScript コードの下に次のものを書いてみてください。それから保存して再読み込みしましょう。</p> + +<pre class="brush: js notranslate">const person = {};</pre> + +<p>ブラウザの <a href="/ja/docs/Learn/Common_questions/What_are_browser_developer_tools#The_JavaScript_console">JavaScript コンソール</a>を開いて、<code>person</code> と入力して、 <kbd>Enter</kbd>/<kbd>Return</kbd> を押してください。以下のいずれかの行に似た結果が得られるはずです。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="punctuation token">[</span>object Object<span class="punctuation token">]</span> +Object <span class="punctuation token">{</span> <span class="punctuation token">}</span> +<span class="punctuation token">{</span> <span class="punctuation token">}</span></code></pre> + +<p>よくやりましたね! まずは最初のオブジェクトができました。でもこれだけでは空のオブジェクトであまり役には立ちません。さらにオブジェクトを変更してみましょう。</p> + +<pre class="brush: js notranslate">const person = { + name: ['Bob', 'Smith'], + age: 32, + gender: 'male', + interests: ['music', 'skiing'], + bio: function() { + alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }, + greeting: function() { + alert('Hi! I\'m ' + this.name[0] + '.'); + } +}; +</pre> + +<p>保存して再読み込みした後で、JavaScript コンソールにいくつか入力してみましょう。</p> + +<pre class="brush: js notranslate">person.name +person.name[0] +person.age +person.interests[1] +person.bio() +person.greeting()</pre> + +<p>オブジェクトから、データと機能を追加することができました。これで簡単な書き方で情報が引き出せます。</p> + +<div class="note"> +<p><strong>注</strong>: もし動かないようなら、完成版のソースコードと見比べてみてください (完成版: <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-finished.html">oojs-finished.html</a> さらに<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-finished.html">ライブ版もあります</a>) 。ライブ版は空白の画面ですが、それで OK です。また開発ツールを開いて上記のコマンドを入力してオブジェクトの構造を見てみます。</p> +</div> + +<p>さて、何が起きているのでしょうか。オブジェクトには複数のメンバーがあり、それぞれに名前がついていて(例えば上の例では <code>name</code> や <code>age</code>)、それぞれに値 (<code>['Bob', 'Smith']</code> や <code>32</code>) があります。それぞれの名前と値の組はカンマ ( , ) で区切られていて、名前と値はコロン ( : ) で区切られています。常にそのように書きます。</p> + +<pre class="brush: js notranslate">const objectName = { + member1Name: member1Value, + member2Name: member2Value, + member3Name: member3Value +}</pre> + +<p>メンバーの値はほとんど何でも大丈夫です。例えば、先ほどの例では文字列、数値、2 つの配列に 2 つの関数でした。最初の 4 つはデータ項目でそのオブジェクトの<strong>プロパティ</strong>と呼ばれます。後ろの 2 つはオブジェクトの持つデータを使用して何かをする関数でオブジェクトの<strong>メソッド</strong>と呼ばれます。</p> + +<p>このように記号を使って書くオブジェクトは後で出てくるクラスを使用して生成する方法と対比して<strong>オブジェクトリテラル</strong>と呼ばます。</p> + +<p>オブジェクトリテラルを使用してオブジェクトを生成する方法はとても一般的で、ある法則に則って構造化、関連付けられたデータをやり取りするときによく使います。(例えばサーバーにリクエストを送ったり、データベースに保存したり。) ある一つのオブジェクトを送るほうが複数の項目を何回かに分けて送るよりも効率的で、名前を用いて検索するときなどには、配列よりも扱いやすいときがあります。</p> + +<h2 id="Dot_notation" name="Dot_notation">ドットによる記述</h2> + +<p>先ほどの例では、オブジェクトのプロパティとメソッドに対して、<strong>ドット記法</strong>を用いてアクセスしました 。オブジェクト名 (person) は<strong>名前空間</strong>として機能します。オブジェクト内に<strong>カプセル化</strong>されたものにアクセスするには、まずこのオブジェクト名を入力する必要があります。次に、ドット ( . ) を書いて、それからアクセスしたい項目を記述します。項目になりうるのは、単純なプロパティの名前や、配列の要素や、そのオブジェクトのメソッドの 1 つへの呼び出しなどです。次に例を示します:</p> + +<pre class="brush: js notranslate">person.age +person.interests[1] +person.bio()</pre> + +<h3 id="Sub-namespaces" name="Sub-namespaces">サブ名前空間</h3> + +<p>オブジェクトの内部にさらにほかのオブジェクトを持つことも可能です。例えば、先の例で、<code>name</code> メンバーを、</p> + +<pre class="brush: js notranslate">name: ['Bob', 'Smith'],</pre> + +<p>以下のように変更してみましょう。</p> + +<pre class="brush: js notranslate">name : { + first: 'Bob', + last: 'Smith' +},</pre> + +<p>これで簡単に<strong>サブ名前空間</strong>を作り出すことができました。難しそうに聞こえるかもしれませんが、ただ単に項目をドットを用いて数珠つなぎにつないでいけばいいのです。コンソールで試してください。</p> + +<pre class="brush: js notranslate">person.name.first +person.name.last</pre> + +<p><strong>重要</strong>: この時点で下の書き方をしていたところは、以下のように変えなければなりません。</p> + +<pre class="brush: js notranslate">name[0] +name[1]</pre> + +<p>を、</p> + +<pre class="brush: js notranslate">name.first +name.last</pre> + +<p>のようにしなければ、メソッドが動かなくなってしまうでしょう。</p> + +<h2 id="Bracket_notation" name="Bracket_notation">角括弧による記述</h2> + +<p>オブジェクトのプロパティにアクセスするもう一つの手段として角括弧を用いた記法があります。</p> + +<pre class="brush: js notranslate">person.age +person.name.first</pre> + +<p>このように書く代わりに、</p> + +<pre class="brush: js notranslate">person['age'] +person['name']['first']</pre> + +<p>のように書きます。</p> + +<p>これは配列の添え字によく似ています。数字の代わりに、名前を用いて関連付けられたメンバーの値にアクセスするだけで、実はほとんど同じなのです。このようなオブジェクトを<strong>連想配列</strong>といい、配列が数字によって値を格納しているように、文字列によって値を格納しています。</p> + +<h2 id="Setting_object_members" name="Setting_object_members">オブジェクトメンバーの設定</h2> + +<p>今まではオブジェクトメンバーからの引き出す (<strong>取得する</strong>) 方法だけを見てきましたが、値を設定するメンバーを宣言することで、オブジェクトのメンバーに値を<strong>設定</strong> (更新) することもできます。(ドットを使用した書き方でも、角括弧を使用した書き方でも構いません。)</p> + +<pre class="brush: js notranslate">person.age = 45; +person['name']['last'] = 'Cratchit';</pre> + +<p>これらの行を入力してみて、実際に値が変わったか調べてみましょう。</p> + +<pre class="brush: js notranslate">person.age +person['name']['last']</pre> + +<p>メンバーの値を設定するのは存在するプロパティやメソッドの更新だけにはとどまりません。まったく新しいメンバーを追加することもできるのです。JS コンソールで次のものを試してみてください。</p> + +<pre class="brush: js notranslate">person['eyes'] = 'hazel'; +person.farewell = function() { alert("Bye everybody!"); }</pre> + +<p>新しいメンバーが追加されたことを確認してみましょう。</p> + +<pre class="brush: js notranslate">person['eyes'] +person.farewell()</pre> + +<p>角括弧での書き方の良いところは、動的にメンバーの値を設定できるだけでなく、メンバーの名前も追加できるところです。例えば、ユーザーの情報として 2 つのテキストフィールドに名前と値を入力してもらい、人により個別のデータを設定したいとします。そういった値を以下のように取得します。</p> + +<pre class="brush: js notranslate">let myDataName = nameInput.value; +let myDataValue = nameValue.value;</pre> + +<p>そうして、取得したメンバー名と値を次のように <code>person</code> オブジェクトに設定します。</p> + +<pre class="brush: js notranslate">person[myDataName] = myDataValue;</pre> + +<p>この動作を確認するため、先ほどのコードの <code>person</code> オブジェクトの中括弧に続いて、次の行をコードに追加してみてください。</p> + +<pre class="brush: js notranslate">let myDataName = 'height'; +let myDataValue = '1.75m'; +person[myDataName] = myDataValue;</pre> + +<p>そして、保存して再度読み込んで、次の行をテキストボックスに入力してみてください。</p> + +<pre class="brush: js notranslate">person.height</pre> + +<p>上記の方法を使用してオブジェクトにプロパティを追加することは、ドット記法ではできません。ドット記法は、名前を指す変数ではなく、書いたとおりのメンバー名のみ受け入れることができます。</p> + +<h2 id="What_is_this" name="What_is_this">"this" とは何か</h2> + +<p>メソッドの中で、少し見慣れない点に気付いたかもしれません。 次の例でその点について考えてみましょう。</p> + +<pre class="brush: js notranslate">greeting: function() { + alert('Hi! I\'m ' + this.name.first + '.'); +}</pre> + +<p>"this" とは何だろうと思ったことでしょう。 この <code>this</code> キーワードはコードの中がその中で書かれている、現在のオブジェクトを参照しています。なので、この場合では <code>person</code> を指します。 なぜ <code>this</code> の代わりに単に <code>person</code> と書かないのでしょうか。 この後 <a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向</a> の記事で見るように、コンストラクター等を書き始めるときに <code>this</code> は非常に便利です。メンバーのコンテキストが変わったとき(例えば 2 つの異なる <code>person</code> オブジェクトのインスタンスは、異なる名前を持っているが、greeting メソッドでそれぞれ自身の名前を使用したいとき)に常に正しい値を保証してくれます。</p> + +<p>それでは、簡略化した <code>person</code> オブジェクトを使って、その意味を説明していきましょう。</p> + +<pre class="brush: js notranslate">const person1 = { + name: 'Chris', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +const person2 = { + name: 'Deepti', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>この場合、<code>person1.greeting()</code> は "Hi! I'm Chris." を出力します。一方、<code>person2.greeting()</code> は "Hi! I'm Deepti." を出力します。しかし、どちらの場合も、そのメソッド部分のコードは全く同じです。先に述べたように <code>this</code> はそのコードが中にあるオブジェクトと等しいです — これは手作業でオブジェクトリテラルを書くときにはそれ程便利ではありませんが、動的にオブジェクトを生成する(例えばコンストラクターを使う)ときにとても効果的です。これは、この後によりはっきりとするでしょう。</p> + +<h2 id="Youve_been_using_objects_all_along" name="Youve_been_using_objects_all_along">ずっとオブジェクトを使ってきた</h2> + +<p>これらの例を通して、既に使ってきたドット記述と非常に似ていると考えたかもしれません。なぜならこのコースを通してそのような方法を使用してきたからです。組み込みのブラウザー API や JavaScript オブジェクトを使う例への取り組みを通していつもオブジェクトを使用してきました。なぜならそのような機能は、基本的なカスタム例よりも複雑ではありますが、ここまで見てきたものと全く同種のオブジェクト構造を使うことで構築されているからです。</p> + +<p>だから、このように文字列のメソッドを使うとき:</p> + +<pre class="brush: js notranslate">myString.split(',');</pre> + +<p><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code> クラスのインスタンスで利用できるメソッドを使用しています。コードの中で文字列を作成するときにはいつでも、その文字列は自動的に <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code> クラスのインスタンスとして生成されます。そしてそのために、いくつかの共通なメソッドやプロパティを使用することができます。</p> + +<p>次の行のようにドキュメントオブジェクトモデルにアクセスするときは、</p> + +<pre class="brush: js notranslate">const myDiv = document.createElement('div'); +const myVideo = document.querySelector('video');</pre> + +<p><code><a href="/ja/docs/Web/API/Document">Document</a></code> クラスのインスタンスで使用可能なメソッドを使っています。各ウェブページが読み込まれると、<code>document</code> と呼ばれる <code>Document</code> のインスタンスが作られ、それはウェブページ全体の構造、コンテンツ、その URL 等その他の機能を表現します。もう一度述べますが、これはいくつかの共通なメソッドやプロパティを使用できることを意味します。</p> + +<p>今まで使用してきた、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> や </span></font></code><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code> 等の、他の多くの組み込みのオブジェクトや API でも全く同じです。</p> + +<p>組み込みのオブジェクトと API では常に自動でオブジェクトのインスタンスが生成される訳ではないことを注意する必要があります。例えば、モダンなブラウザーがシステム通知を発行することを許可する <a href="/ja/docs/Web/API/Notifications_API">Notifications API</a> では、発行したい各通知のためにコンストラクターを使用した新しいオブジェクトを生成する必要があります。JavaScript コンソールに次を入力してみてください。</p> + +<pre class="brush: js notranslate">const myNotification = new Notification('Hello!');</pre> + +<p>コンストラクターは後の記事でもう一度見ることができます。</p> + +<div class="note"> +<p><strong>注</strong>: オブジェクトのやり取りを<strong>メッセージの受け渡し</strong>と考えると便利です。オブジェクトが他のオブジェクトにある処理の実行を要求したとき、そのオブジェクトはメソッドを通じて他のオブジェクトにメッセージを送信して、そして応答を待ちます。ご存知の通り、応答とは返り値のことです。</p> +</div> + +<h2 id="Test_your_skills!" name="Test_your_skills!">スキルをテストしましょう!</h2> + +<p>この記事の最後に到達しましたが、最も大事な情報を覚えていますか?次に移動する前に、この情報を保持しているか検証するテストがあります — <a href="/ja/docs/Learn/JavaScript/Objects/Test_your_skills:_Object_basics">Test your skills: Object basics</a> を見てください。</p> + +<h2 id="Summary" name="Summary">おさらい</h2> + +<p>お疲れ様でした。最初の JS オブジェクトの記事の終わりまで到達しました。JavaScript のオブジェクトがどのように機能するかについて、良い考えを得ることができたのではないでしょうか。記事では、簡単なオリジナルオブジェクトの作成を含んでいました。オブジェクトは関連するデータと機能を保存する構造として非常に便利であることも理解しなければいけません。もし別々の変数と関数として、<code>person</code> オブジェクトのすべてのプロパティとメソッドを記録していくとすると、非効率でありストレスが溜まります。そして同じ名前の他の変数や関数をクラッシュしてしまう危険性も抱えてしまいます。オブジェクトは有害な方法を避けて、パッケージの中で安全に鍵をして情報を守ってくれます。</p> + +<p>次の記事ではオブジェクト指向プログラミング (OOP) 理論を見ていきます。そして、JavaScript ではそのような素晴らしい技術を使うことができます。</p> + +<p>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/index.html b/files/ja/learn/javascript/objects/index.html new file mode 100644 index 0000000000..65df0e0ece --- /dev/null +++ b/files/ja/learn/javascript/objects/index.html @@ -0,0 +1,53 @@ +--- +title: JavaScript オブジェクト入門 +slug: Learn/JavaScript/Objects +tags: + - Article + - Assesment + - Beginner + - CodingScripting + - Guide + - JavaScript + - Learn + - Objects + - Tutorial + - 学習 +translation_of: Learn/JavaScript/Objects +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">JavaScript では、文字列や配列などの JavaScript のコア機能から、JavaScript の最上部に構築されたブラウザ API まで、ほとんどのものがオブジェクトです。関連する関数や変数を効率的なパッケージにカプセル化して、便利なデータコンテナーとして動作する独自のオブジェクトを作成することもできます。JavaScript のオブジェクトベースの性質を理解することは、言語に関する知識をさらに深め、より効率的なコードを書く場合に重要です。したがって、この役立つモジュールを用意しました。ここではオブジェクトの理論と構文を詳しく説明し、独自のオブジェクトを作成する方法を見ていきます。</p> + +<h2 id="Prerequisites" name="Prerequisites">前提条件</h2> + +<p>このモジュールを始める前に、 HTML と CSS にいくらか精通している必要があります。JavaScript を始める前に <a href="https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Introduction">HTML 入門</a>と <a href="https://developer.mozilla.org/ja/docs/Learn/CSS/Introduction_to_CSS">CSS 入門</a>をひととおり学習することをオススメします。</p> + +<p>また、JavaScript オブジェクトを詳細に調べる前に、JavaScript の基本についていくらか精通している必要があります。このモジュールを試す前に、<a href="/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a> と <a href="/ja/docs/Learn/JavaScript/Building_blocks">JavaScript の構成要素</a>を通して学習してください。</p> + +<div class="note"> +<p><strong>注記 </strong>: もしあなたが作業しているコンピューター・タブレットやその他のデバイスで自分でファイルを作れない場合は、<a href="http://jsbin.com/">JSBin</a> や <a href="https://thimble.mozilla.org/">Thimble</a> といったようなオンラインコーディングプログラムで (ほとんどの場合) 試すことができます。</p> +</div> + +<h2 id="Guides" name="Guides">ガイド</h2> + +<dl> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/Basics">オブジェクトの基本</a></dt> + <dd>JavaScript オブジェクトについて記載している最初の記事では、基本的な JavaScript オブジェクト構文を見てみます。コースの初期段階で既に見た JavaScript の機能を再び見てみたり、すでに扱っている機能の多くは実際にオブジェクトであるという事実を繰り返し述べています。</dd> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></dt> + <dd>まずオブジェクト指向 JavaScript (OOJS) に焦点を当てます — この記事では、オブジェクト指向プログラミング (OOP) 理論の基本ビューを示し、次に JavaScript がコンストラクタ関数を介してオブジェクトクラスをエミュレートする方法と、オブジェクトインスタンスを作成する方法について説明します。</dd> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">オブジェクトプロトタイプ</a></dt> + <dd>プロトタイプは、JavaScript オブジェクトが互いに機能を継承するメカニズムであり、古典的なオブジェクト指向プログラミング言語の継承メカニズムとは異なる働きをします。この記事では、その違いを探り、プロトタイプチェーンの仕組みを説明し、prototype プロパティを使用して既存のコンストラクタにメソッドを追加する方法を見ていきます。</dd> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></dt> + <dd>OOJS の大部分の詳細がこれまで説明されているため、この記事では、「親」クラスから機能を継承する「子」オブジェクトクラス (のコンストラクタ) を作成する方法を示します。また OOJS をいつどこで使用するかについてのアドバイスも提供しています。</dd> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></dt> + <dd>JavaScript Object Notation (JSON) は、JavaScript オブジェクト構文に基づいて構造化されたデータを表現するための標準のテキストベースのフォーマットであり、ウェブサイト上でデータを表現し、送信するために一般的に使用されます (すなわち、サーバーからクライアントへデータを送信して、その結果ウェブページ上に表示することができます)。これはとても良く見るものなので、この記事では、JSON を解析してその中のデータ項目にアクセスしたり、独自の JSON を記述したりするなど、JavaScript を使用して JSON を操作するために必要なことをすべて説明します。</dd> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト構築の練習</a></dt> + <dd>これまでの記事では、基本的な JavaScript オブジェクトの理論と構文の詳細をすべて見てもらい、あなたには出発できるしっかりとした基本が与えられました。この記事では実践的なエクササイズを行い、もっと楽しい色とりどりの色付きのボールを作成するカスタム JavaScript オブジェクトを作る練習をしていきます。</dd> +</dl> + +<h2 id="Assessments" name="Assessments">評価</h2> + +<dl> + <dt><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールのデモへの機能の追加</a></dt> + <dd>この評価では、前の記事のバウンスボールデモを出発点として使用し、新しい興味深い機能を追加する予定です。</dd> +</dl> diff --git a/files/ja/learn/javascript/objects/inheritance/index.html b/files/ja/learn/javascript/objects/inheritance/index.html new file mode 100644 index 0000000000..7830f5a676 --- /dev/null +++ b/files/ja/learn/javascript/objects/inheritance/index.html @@ -0,0 +1,412 @@ +--- +title: JavaScript での継承 +slug: Learn/JavaScript/Objects/Inheritance +tags: + - Article + - CodingScripting + - Inheritance + - JavaScript + - OOJS + - OOP + - Object + - Prototype + - 'l10n:priority' + - 初心者 + - 学習 +translation_of: Learn/JavaScript/Objects/Inheritance +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">OOJS のぞっとするような細部はほとんど説明されたので、ここでは”親”クラスからの機能を継承する”子供”のオブジェクトクラス (コンストラクタ) の生成方法について解説します。さらに、いつ、どこで OOJS を使うかについてのアドバイスを提示し、最新の ECMAScript の構文でクラスがどのように扱われるかを見ていきます。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提知識</th> + <td>基本的なコンピュータの知識および利用能力、HTML と CSS への基本的な理解、JavaScript の基本 (<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/First_steps">第一歩</a>と<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks">構成要素</a>を参照) と OOJS の基本 (<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics">オブジェクト入門</a>) に慣れている。</td> + </tr> + <tr> + <th scope="row">目的:</th> + <td>JavaScript でどのように継承ができるようになっているかを理解していること。</td> + </tr> + </tbody> +</table> + +<h2 id="Prototypal_inheritance" name="Prototypal_inheritance">プロトタイプでの継承</h2> + +<p>ここまで動作している継承 ー プロトタイプチェーンがどのように動作するか、どのようにメンバーが繋がるチェーンから継承されるのかを見てきました。しかし、これらの大半はブラウザーの組み込み関数で実行されています。我々が他のオブジェクトから継承したオブジェクトを作成するには JavaScript でどのようにするのでしょうか。</p> + +<p>具体的な例をjj使ってどのようの継承が行われているかを見てゆきましょう。</p> + +<h2 id="Getting_started" name="Getting_started">さあ始めてみよう</h2> + +<p>まず、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-start.html">oojs-class-inheritance-start.html</a> ファイルをローカルにコピーしましょう (あるいは<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-start.html">ライブ版の実行</a>でも確認できます)。ここでこのモジュールで幅広く使用されてきた <code>Person()</code> というコンストラクタの例を見つけることができます。わずかな違いがあって、コンストラクタ内部にプロパティのみが定義されています。</p> + +<pre class="brush: js notranslate">function Person(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +};</pre> + +<p>メソッドはすべてコンストラクタのプロトタイプとして定義されています。例えば、</p> + +<pre class="brush: js notranslate">Person.prototype.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); +};</pre> + +<div class="note"> +<p><strong>注意</strong>: ソースコードに、<code>bio()</code> と <code>farewell()</code> が定義されています。後ほどこれらのメソッドがどのようにほかのコンストラクタで継承されるのかを確認します。</p> +</div> + +<p><code>Teacher</code> クラスを作成したい場合を考えましょう。これは最初のオブジェクト指向の特徴にて述べたもののようなクラスで、<code>Person</code> からすべてのメンバーを継承しますが、次のものも内包しています。</p> + +<ol> + <li>新しいプロパティの <code>subject</code> — これはその先生の教える科目を格納します。</li> + <li>上書きされた <code>greeting()</code> メソッド、標準の <code>greeting()</code> メソッドよりわずかに固く感じられる — 学校で生徒に語りかける先生により相応しい。</li> +</ol> + +<h2 id="Defining_a_Teacher_constructor_function" name="Defining_a_Teacher_constructor_function">Teacher() コンストラクタの機能を定義しよう</h2> + +<p>われわれのまずすべき事は <code>Teacher()</code> コンストラクタを作成する事です — 以下に続くコードを既存コードの下に追加してください。</p> + +<pre class="brush: js notranslate">function Teacher(first, last, age, gender, interests, subject) { + Person.call(this, first, last, age, gender, interests); + + this.subject = subject; +}</pre> + +<p>これは多くの点で Person コンストラクタと似ていますが、これまでに見てきたものと異なったものがあります— <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call()</a></code> 関数です。この関数は基本的にその他の場所 (ただし現在のコンテキスト) で定義された関数から呼ぶことができます。最初の引数は関数を実行するときに使用することのできる <code>this</code> の値を表します、また他の引数は実行される関数に渡されるべき値です。</p> + +<p><code>Teacher()</code> コンストラクタは継承元の <code>Person()</code> コンストラクタと同じ引数を取りたいため、 <code>call()</code> を呼び出して、すべての引き数を引数として渡します。</p> + +<p>コンストラクタの最後の行は、先生が行うべきであり、一般の人が持たない新たな <code>subject</code>(授業) のプロパティを定義しています。</p> + +<p>注意として、下記のソースのように、このようにシンプルにも書けます。</p> + +<pre class="brush: js notranslate">function Teacher(first, last, age, gender, interests, subject) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.subject = subject; +}</pre> + +<p>しかしながらこれはただ改めてプロパティを再定義しているだけで、 <code>Person()</code> から継承していません、そのため、説明しようとしたポイントが伝わりません。またコード行数が多くもなります。</p> + +<h3 id="Inheriting_from_a_constructor_with_no_parameters" name="Inheriting_from_a_constructor_with_no_parameters">引数なしのコンストラクタからの継承</h3> + +<p>もし継承したコンストラクタがパラメータからプロパティの値を取得しない場合、 <code>call()</code> の呼び出しで追加の引数を指定する必要がないことを示しておきます。そのため、例えば、このような本当にシンプルなものがある場合、</p> + +<pre class="brush: js notranslate">function Brick() { + this.width = 10; + this.height = 20; +}</pre> + +<p>このように書くことで <code>width</code> と <code>height</code> プロパティを継承することができます(もちろん、下に挙げる数行のステップの様にすることもできます)。</p> + +<pre class="brush: js notranslate">function BlueGlassBrick() { + Brick.call(this); + + this.opacity = 0.5; + this.color = 'blue'; +}</pre> + +<p> <code>call()</code> の中に <code>this</code> だけを記載していることに注意して下さい— 引数を介して親より設定されるどのプロパティも継承しないので他の引数は不要です。</p> + +<h2 id="Setting_Teachers_prototype_and_constructor_reference" name="Setting_Teachers_prototype_and_constructor_reference">Teacher()のプロトタイプ とコンストラクタの参照への設定方法</h2> + +<p>今まではすべて順調でしたが、1点問題があります。新しいコンストラクタを定義して、その中に 1 つの <code>prototype</code> プロパティを持たせ、これはデフォルトでただ自身のコンストラクタ関数への参照を保持しています。Person のコンストラクタの <code>prototype</code> プロパティへのメソッド群は持っていません。このことを見てみたいのならば <code>Object.getOwnPropertyNames(Teacher.prototype)</code> をテキスト入力フィールドや JavaScript コンソールへ入力を試してみてください。そして再度入力する時には、<code>Teacher</code> を <code>Person</code> で置き換えてみてください。新しいコンストラクタもそれらのメソッドを継承していません。このことを確認するために、<code>Person.prototype.greeting</code> と <code>Teacher.prototype.greeting</code> の出力結果を比べてみてください。<code>Person()</code> のプロトタイプに定義されたメソッドを継承するために <code>Teacher()</code> を生成する必要があります。ではどのようにすればよいのでしょうか。</p> + +<ol> + <li>前回追加した部分の下に以下の行を追加してみましょう: + <pre class="brush: js notranslate">Teacher.prototype = Object.create(Person.prototype);</pre> + ここで我々に馴染み深い <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code> に再度助けてもらいましょう。この場合に新しいオブジェクトを作ってそれを <code>Teacher.prototype</code> の値とするのに使います。新しいオブジェクトは <code>Person.prototype</code> を自身のプロトタイプとして保持し、それがゆえに(必要となる時には) <code>Person.prototype</code> 上で利用できるすべてのメソッドを継承します。</li> + <li>先に進む前にもう一つやることがあります。<br> + 最後の行を追加した後、<code>Teacher.</code><code>prototype</code> の <code>constructor</code> プロパティは <code>Person()</code> と同じになりました。なぜなら、<code>Person.prototype</code> からプロパティを継承するオブジェクトを参照するように <code>Teacher.prototype</code> を設定しただけだからです。コードを保存し、ブラウザでページを読み込み、コンソールに <code>Teacher.prototype.constructor</code> と入力して確認してみてください。</li> + <li>これは問題になるかもしれません、なので以下の内容をすぐに設定しましょう。 ソースコードにまた戻って最後に以下の行を追加しましょう。 + <pre class="brush: js notranslate">Object.defineProperty(Teacher.prototype, 'constructor', { + value: Teacher, + enumerable: false, // 'for in'ループで現れないようにする + writable: true });</pre> + </li> + <li>ソースコードを保存およびページの再読み込みを行って、 <code>Teacher.prototype.constructor</code> と入力したならば <code>Teacher()</code> と返すでしょう、希望した通りに <code>Person()</code> から継承することができました!</li> +</ol> + +<h2 id="Giving_Teacher_a_new_greeting_function" name="Giving_Teacher_a_new_greeting_function">Teacher() に greeting() ファンクションを付け加える</h2> + +<p>コードを完成させる前に、<code>Teacher()</code> コンストラクタに新たに <code>greeting()</code> 関数を追加する必要があります。</p> + +<p>このようにする一番簡単な方法は <code>Teacher()</code> のプロトタイプに定義することです — コードの最後に以下のコードを追加します。</p> + +<pre class="brush: js notranslate">Teacher.prototype.greeting = function() { + let prefix; + + if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') { + prefix = 'Mr.'; + } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') { + prefix = 'Mrs.'; + } else { + prefix = 'Mx.'; + } + + alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.'); +};</pre> + +<p>これは性別を基にした適切な敬称を使う教師の挨拶を通知します。条件文を使うことで実現します。</p> + +<h2 id="Trying_the_example_out" name="Trying_the_example_out">例を試してみよう</h2> + +<p>これまでのコードをすべて入力し終えているなら、ソースコード(もしくはあなたの用意した同じようなコードに)の最後に続けて <code>Teacher()</code> からオブジェクトインスタンスを生成してみましょう。</p> + +<pre class="brush: js notranslate">let teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');</pre> + +<p>保存し、再読み込みをしたなら、新たな <code>teacher1</code> オブジェクトのプロパティとメソッドにアクセスしてみましょう、例えば。</p> + +<pre class="brush: js notranslate">teacher1.name.first; +teacher1.interests[0]; +teacher1.bio(); +teacher1.subject; +teacher1.greeting(); +teacher1.farewell();</pre> + +<p>これらはすべて正常に動作するはずです。1, 2, 3, 6 行目のクエリは、ジェネリックな <code>Person()</code> コンストラクタ (クラス) から継承されたメンバにアクセスします。4 行目のクエリは、より特殊な <code>Teacher()</code> コンストラクタ (クラス) でのみ利用可能なメンバにアクセスしています。5 行目のクエリは <code>Person()</code> から継承したメンバにアクセスしていますが、<code>Teacher()</code> には同じ名前の独自のメンバがあるため、そのメンバにアクセスしています。</p> + +<div class="note"> +<p><strong>注記</strong>: もしここまでの例がうまく動作しないなら、あなたのコードと<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">完成版</a>(<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-finished.html">ライブ版</a>も参照)を比較してみてください。</p> +</div> + +<p>ここで述べている手法は JavaScript でクラスを継承する唯一の方法ではなく、問題なく動作し、JavaScript でのどのように実装するかの良いアイデアを提示しています。</p> + +<p>また JavaScript でより明瞭に継承を行えるようにした新しい{{glossary("ECMAScript")}}の機能(<a href="/ja/docs/Web/JavaScript/Reference/Classes">Classes</a> を参照)にも興味を持つかもしれません。ここではそれらについて言及はしませんでした、それはまだブラウザー間で幅広くサポートされていないためです。一連の記事で検討してきた他のコード構造はすべて、IE9 やそれ以前のバージョンといった、はるか以前よりサポートされており、それより早くからのサポートを確認する方法となります。</p> + +<p>一般的な方法は JavaScript ライブラリを使用することです — よく知られた選択肢のうちの大部分は、よりたやすく素早く利用できる簡易な機能セットを持っています。例えば <a href="http://coffeescript.org/#classes">CoffeeScript</a> は <code>class</code>, <code>extends</code> などを提供します。</p> + +<h2 id="A_further_exercise" name="A_further_exercise">追加の特訓</h2> + +<p><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">OOP 理論のセクション</a>では、概念として <code>Student</code> クラスも取り上げました。このクラスは <code>Person</code> のすべての機能を継承しており、また <code>Person</code> とは異なる <code>Teacher</code> の greeting よりもはるかにくだけた <code>greeting()</code> メソッドを持っています。このセクションで生徒の挨拶がどのように見えるかを見て、<code>Person()</code> のすべての機能を継承し、異なる <code>greeting()</code> 関数を実装した独自の <code>Student()</code> コンストラクタを実装してみてください。</p> + +<div class="note"> +<p><strong>注記</strong>: もしここまでの例がうまく動作しないなら、あなたのコードと<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">完成版</a>(<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-finished.html">動作するライブ版</a>も参照)を比較してみてください。</p> +</div> + +<h2 id="Object_member_summary" name="Object_member_summary">Object メンバーの概要</h2> + +<p>要約すると、気になるプロパティ/メソッドは4種類あります。</p> + +<ol> + <li>コンストラクタ関数の内部で定義され、オブジェクトインスタンスに与えられるもの。独自のカスタムコードでは、コンストラクタの内部で <code>this.x = x</code> 型の行を使用して定義されたメンバです。組み込みのブラウザコードでは、オブジェクトインスタンス (通常は <code>new</code> キーワードを使用してコンストラクタを呼び出すことで作成されます。例: <code>let myInstance = new myConstructor()</code>) のみが利用可能なメンバです</li> + <li>コンストラクタ自身で直接定義されたもので、コンストラクタ上でのみ利用可能なもの。これらは一般的に組み込みのブラウザオブジェクトでのみ利用可能であり、インスタンスではなくコンストラクタに直接連結されていることで認識されます。たとえば <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code> などです。これらは<strong>静的プロパティ/メソッド</strong>としても知られています</li> + <li>コンストラクタのプロトタイプに定義されているもので、すべてのインスタンスに継承され、オブジェクトクラスを継承しているもの。これらには、コンストラクタの <code>prototype</code> プロパティに定義されている任意のメンバ (例: <code>myConstructor.prototype.x()</code>) が含まれます</li> + <li>これらは、上で見たようにコンストラクタがインスタンス化されたときに作成されるオブジェクト (例えば <code>let teacher1 = new Teacher('Chris');</code> の後に <code>teacher1.name</code>)、またはオブジェクトリテラル (<code>let teacher1 = { name : 'Chris' }</code> の後に <code>teacher1.name</code>) のいずれかであることができます</li> +</ol> + +<p>もしどれがどれを指すかを区別できないのであれば、まだ気にしないでください — あなたはまだ学習中で、実践を通じて精通することでしょう。</p> + +<h2 id="ECMAScript_2015_Classes" name="ECMAScript_2015_Classes">ECMAScript 2015 のクラス</h2> + +<p>ECMAScript 2015では、C++ や Java のクラスに似た、より簡単で洗練された構文を使用して再利用可能なクラスを記述する方法として、JavaScript に<a href="/ja/docs/Web/JavaScript/Reference/Classes">クラス構文</a>を導入しています。このセクションでは、Person と Teacher の例をプロトタイプの継承からクラスに変更して、どのようにして行うかを示します。</p> + +<div class="note"> +<p><strong>メモ</strong>: この近代的なクラスの作成方法は現在のすべてのブラウザでサポートされていますが、この構文をサポートしていないブラウザ (特に Internet Explorer) をサポートする必要があるプロジェクトで作業する場合に備えて、基本的なプロトタイプの継承の仕組みについて知っておくことはまだ価値があります。</p> +</div> + +<p>Person の例を class-style で書き直したバージョンを見てみましょう:</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">class</span> <span class="class-name token">Person</span> <span class="punctuation token">{</span> + <span class="function token">constructor</span><span class="punctuation token">(</span>first<span class="punctuation token">,</span> last<span class="punctuation token">,</span> age<span class="punctuation token">,</span> gender<span class="punctuation token">,</span> interests<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>name <span class="operator token">=</span> <span class="punctuation token">{</span> + first<span class="punctuation token">,</span> + last + <span class="punctuation token">}</span><span class="punctuation token">;</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>age <span class="operator token">=</span> age<span class="punctuation token">;</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>gender <span class="operator token">=</span> gender<span class="punctuation token">;</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>interests <span class="operator token">=</span> interests<span class="punctuation token">;</span> + <span class="punctuation token">}</span> + + <span class="function token">greeting</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span><span class="template-string token"><span class="string token">`Hi! I'm </span><span class="interpolation token"><span class="interpolation-punctuation punctuation token">${</span><span class="keyword token">this</span><span class="punctuation token">.</span>name<span class="punctuation token">.</span>first<span class="interpolation-punctuation punctuation token">}</span></span><span class="string token">`</span></span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">;</span> + + <span class="function token">farewell</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span><span class="template-string token"><span class="string token">`</span><span class="interpolation token"><span class="interpolation-punctuation punctuation token">${</span><span class="keyword token">this</span><span class="punctuation token">.</span>name<span class="punctuation token">.</span>first<span class="interpolation-punctuation punctuation token">}</span></span><span class="string token"> has left the building. Bye for now!`</span></span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<p><a href="/ja/docs/Web/JavaScript/Reference/Statements/class">class</a>ステートメントは、新しいクラスを作成していることを示します。 このブロックの中で、クラスのすべての機能を定義します。</p> + +<ul> + <li><code><a href="/ja/docs/Web/JavaScript/Reference/Classes/constructor">constructor()</a></code> メソッドは、<code>Person</code>クラスを表すコンストラクタ関数を定義します</li> + <li><code>greeting()</code> と <code>farewell()</code> はクラスメソッドです。クラスに関連付けたいメソッドは、コンストラクタの後に定義されます。この例では、コードを読みやすくするために、文字列連結ではなく<a href="/ja/docs/Web/JavaScript/Reference/template_strings">テンプレート文字列</a>を使用しています</li> +</ul> + +<p>以前と同じように<a href="/ja/docs/Web/JavaScript/Reference/Operators/new">new演算子</a>を使用してオブジェクトインスタンスをインスタンス化できるようになりました。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">let</span> han <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Person</span><span class="punctuation token">(</span><span class="string token">'Han'</span><span class="punctuation token">,</span> <span class="string token">'Solo'</span><span class="punctuation token">,</span> <span class="number token">25</span><span class="punctuation token">,</span> <span class="string token">'male'</span><span class="punctuation token">,</span> <span class="punctuation token">[</span><span class="string token">'Smuggling'</span><span class="punctuation token">]</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +han<span class="punctuation token">.</span><span class="function token">greeting</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="comment token">// Hi! I'm Han</span> + +<span class="keyword token">let</span> leia <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Person</span><span class="punctuation token">(</span><span class="string token">'Leia'</span><span class="punctuation token">,</span> <span class="string token">'Organa'</span><span class="punctuation token">,</span> <span class="number token">19</span><span class="punctuation token">,</span> <span class="string token">'female'</span><span class="punctuation token">,</span> <span class="punctuation token">[</span><span class="string token">'Government'</span><span class="punctuation token">]</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +leia<span class="punctuation token">.</span><span class="function token">farewell</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="comment token">// Leia has left the building. Bye for now</span></code></pre> + +<div class="note"> +<p><strong>メモ</strong>: 内部ではクラスはプロトタイプの継承モデルに変換されています。これはシンタックスシュガーです。しかし、私たちはあなたがそれを書く方が簡単だと考えるだろうと確信しています。</p> +</div> + +<h3 id="Inheritance_with_class_syntax" name="Inheritance_with_class_syntax">クラス構文による継承</h3> + +<p>上記では人を表すクラスを作成しました。彼らはすべての人々に共通の一連の属性を持っています。このセクションでは、特殊な<code>Teacher</code>クラスを作成し、現代のクラス構文を使用して<code>Person</code>から継承します。これはサブクラス、またはサブクラスの作成と呼ばれます。<br> + <br> + サブクラスを作成するには <a href="/ja/docs/Web/JavaScript/Reference/Classes/extends">extends キーワード</a>を使用して、クラスの基底となるクラスをJavaScriptに通知します。</p> + +<pre class="brush: js notranslate">constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +} </pre> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super"><code>super()</code></a> 演算子を <code>constructor()</code> 内の最初の項目として定義することで、コードをより読みやすくすることができます。これは親クラスのコンストラクタを呼び出し、そこに定義されている限り、指定したメンバーを<code>super()</code> のパラメータとして継承します。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">class</span> <span class="class-name token">Teacher</span> <span class="keyword token">extends</span> <span class="class-name token">Person</span> <span class="punctuation token">{</span> + <span class="function token">constructor</span><span class="punctuation token">(</span>first<span class="punctuation token">,</span> last<span class="punctuation token">,</span> age<span class="punctuation token">,</span> gender<span class="punctuation token">,</span> interests<span class="punctuation token">,</span> subject<span class="punctuation token">,</span> grade<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">super</span><span class="punctuation token">(</span>first<span class="punctuation token">,</span> last<span class="punctuation token">,</span> age<span class="punctuation token">,</span> gender<span class="punctuation token">,</span> interests<span class="punctuation token">)</span><span class="punctuation token">;</span> + + <span class="comment token">// 科目と学年は教師によって決まっている</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>subject <span class="operator token">=</span> subject<span class="punctuation token">;</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>grade <span class="operator token">=</span> grade<span class="punctuation token">;</span> + <span class="punctuation token">}</span> +<span class="punctuation token">}</span></code></pre> + +<p><code>Teacher</code>のオブジェクトをインスタンス化するときには、<code>Teacher</code>と<code>Person</code>の両方で定義されたメソッドとプロパティを呼び出すことができます。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">let</span> snape <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Teacher</span><span class="punctuation token">(</span><span class="string token">'Severus'</span><span class="punctuation token">,</span> <span class="string token">'Snape'</span><span class="punctuation token">,</span> <span class="number token">58</span><span class="punctuation token">,</span> <span class="string token">'male'</span><span class="punctuation token">,</span> <span class="punctuation token">[</span><span class="string token">'Potions'</span><span class="punctuation token">]</span><span class="punctuation token">,</span> <span class="string token">'Dark arts'</span><span class="punctuation token">,</span> <span class="number token">5</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +snape<span class="punctuation token">.</span><span class="function token">greeting</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// Hi! I'm Severus.</span> +snape<span class="punctuation token">.</span><span class="function token">farewell</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// Severus has left the building. Bye for now.</span> +snape<span class="punctuation token">.</span>age <span class="comment token">// 58</span> +snape<span class="punctuation token">.</span>subject<span class="punctuation token">;</span> <span class="comment token">// Dark arts</span></code></pre> + +<p>Teachers と同じように、基本クラスを変更せずに <code>Person</code> をさらに特化したものにするために、他のサブクラスを作成できます。</p> + +<div class="note"> +<p><strong>メモ</strong>: この例は、GitHub で <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-class-inheritance.html">es2015-class-inheritance.html</a> として見つけることができます(<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-class-inheritance.html">これも実際に参照してください</a>)。</p> +</div> + +<h2 id="Getters_and_Setters" name="Getters_and_Setters">Getter と Setter</h2> + +<p>作成するクラスの属性の値を変更したい場合や、属性の最終値がわからない場合があります。<code>Teacher</code> の例を使用すると、教師が教材を作成する前にどの教科を教えるか分からないことがあります。<br> + <br> + getter や setter でこのような状況を処理できます。<br> + <br> + getter と setter で Teacher クラスを強化しましょう。私たちが最後に見たときと同じようにクラスが始まります。<br> + <br> + getter と setter はペアで動作します。getter は変数の現在の値を返し、対応する setter は変数の値をひとつの値に変更します。<br> + <br> + 変更された <code>Teacher</code> クラスは次のようになります。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">class</span> <span class="class-name token">Teacher</span> <span class="keyword token">extends</span> <span class="class-name token">Person</span> <span class="punctuation token">{</span> + <span class="function token">constructor</span><span class="punctuation token">(</span>first<span class="punctuation token">,</span> last<span class="punctuation token">,</span> age<span class="punctuation token">,</span> gender<span class="punctuation token">,</span> interests<span class="punctuation token">,</span> subject<span class="punctuation token">,</span> grade<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">super</span><span class="punctuation token">(</span>first<span class="punctuation token">,</span> last<span class="punctuation token">,</span> age<span class="punctuation token">,</span> gender<span class="punctuation token">,</span> interests<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="comment token">// 科目と学年は教師によって決まっている</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>_subject <span class="operator token">=</span> subject<span class="punctuation token">;</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>grade <span class="operator token">=</span> grade<span class="punctuation token">;</span> + <span class="punctuation token">}</span> + + <span class="keyword token">get</span> <span class="function token">subject</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> <span class="keyword token">this</span><span class="punctuation token">.</span>_subject<span class="punctuation token">;</span> + <span class="punctuation token">}</span> + + <span class="keyword token">set</span> <span class="function token">subject</span><span class="punctuation token">(</span>newSubject<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">this</span><span class="punctuation token">.</span>_subject <span class="operator token">=</span> newSubject<span class="punctuation token">;</span> + <span class="punctuation token">}</span> +<span class="punctuation token">}</span></code></pre> + +<p>上のクラスでは、<code>subject</code> プロパティの getter と setter があります。 Nameプロパティを格納するために <strong><code>_</code> </strong>を使用して別の値を作成します。この規約を使用しないと、get または set を呼び出すたびにエラーが発生します。 この時点で:</p> + +<ul> + <li><code>snape</code> オブジェクトの <code>_subject</code> プロパティの現在の値を表示するには、<code>snape.subject</code> getter メソッドを使用します</li> + <li><code>_subject</code> プロパティに新しい値を割り当てるには、<code>snape.subject="new value"</code> setter メソッドを使用できます</li> +</ul> + +<p>以下の例は、動作している2つの機能を示しています。</p> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="comment token">// デフォルトの値をチェックする</span> +console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span>snape<span class="punctuation token">.</span>subject<span class="punctuation token">)</span> <span class="comment token">// Returns "Dark arts"</span> + +<span class="comment token">// 値を変更する</span> +snape<span class="punctuation token">.</span>subject <span class="operator token">= </span><span class="string token">"Balloon animals"</span> <span class="comment token">// Sets _subject to "Balloon animals"</span> + +<span class="comment token">// 新しい値と一致しているか再度チェックする</span> +console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span>snape<span class="punctuation token">.</span>subject<span class="punctuation token">)</span> <span class="comment token">// Returns "Balloon animals"</span></code></pre> + +<div class="note"> +<p><strong>メモ</strong>: この例は、GitHub で <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-class-inheritance.html">es2015-class-inheritance.html</a> として見つけることができます(<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-class-inheritance.html">これも実際に参照してください</a>)。</p> +</div> + +<div class="blockIndicator note"> +<p><strong>メモ</strong>: ゲッターやセッターは、プロパティが要求されたり設定されたりするたびにコードを実行したい場合など、非常に便利な場合があります。しかし、単純なケースでは、ゲッターやセッターを使用しないプレーンなプロパティアクセスで十分です。</p> +</div> + +<h2 id="When_would_you_use_inheritance_in_JavaScript" name="When_would_you_use_inheritance_in_JavaScript">JavaScript でいつ継承を使用するのでしょうか?</h2> + +<p>特にこの最後の記事を読み終えた後、「うーん、これはややこしいな。」と考えることでしょう。ええ、それは正しい感想です。プロトタイプと継承は JavaScript のもっとも複雑な面のいくつかに当たります、しかし多くの JavaScript の能力と柔軟性はそのオブジェクトの構造と継承に由来します、そしてそれがどのように動作するかは理解するに値します。</p> + +<p>ある意味では、常に継承を使用しています。Web API の様々な機能、文字列や配列といったブラウザーに組み込まれたオブジェクトで定義されているメソッド/プロパティを使用するときはいつも、暗黙の内に継承を使用しています。</p> + +<p>コードに継承を使用していることに関して、特に開始時には、そして小さなプロジェクトでは多分頻繁には使っていないでしょう。不要にも関わらず、継承のためだけにオブジェクトおよび継承を使用するのは時間の浪費です。しかしコードの母体が大きくなればなるほど、継承についての必要性が目に付きやすくなってきます。同じような機能を持ついくつものオブジェクトを作成していることに気付いた場合は、共有機能を持つ汎化オブジェクトタイプを作成し、特化オブジェクトタイプでそれらの機能を継承させるのがお手軽であり、便利です。</p> + +<div class="note"> +<p><strong>注記</strong>: プロトタイプチェーンなどを使って JavaScript が動作する方法のために、オブジェクト間での機能の共有をしばしば <strong>移譲</strong> と呼ぶ事があります。特化オブジェクトは汎化オブジェクトタイプから機能的に移譲されています。</p> +</div> + +<p>継承を使用している時、継承をやたら多いレベルに行わないように、メソッドとプロパティをどこに定義したかを注意深く追跡し続けるようにアドバイスされるでしょう。組み込みブラウザーのオブジェクトのプロトタイプを一時的に変更するコードを書き始めることは可能ですが、実際に良い理由がないのであれば、そうすべきではありません。過剰な継承は終わりない混乱や、そんなコードをデバックする時は終わりない痛みに繋がりかねません。</p> + +<p>究極的には、オブジェクトは関数やループのような、自身の固有の役割や長所を活かした、コードの再利用の単なる別の形でもあります。もし関連のある変数や関数の一団を作成していることに気付き、それらすべてを追跡して適切にパッケージ化したいのであれば、オブジェクトは良いアイデアです。オブジェクトはまた、ある所から別の所にデータの集合を渡したい場合にも大変便利です。これらの事柄の両方がコンストラクタや継承を使用する事なく達成できます。もしオブジェクトの単一のインスタンスが必要なだけであれば、オブジェクトリテラルを使用するのが多分より良く、確実に継承は必要ないでしょう。</p> + +<h2 id="Alternatives_for_extending_the_prototype_chain" name="Alternatives_for_extending_the_prototype_chain">プロトタイプチェーンを拡張するための代替案</h2> + +<p>JavaScript では、上で示したものとは別に、オブジェクトのプロトタイプを拡張する方法がいくつかあります。その他の方法についての詳細は、<a href="/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Different_ways_to_create_objects_and_the_resulting_prototype_chain">継承とプロトタイプチェーン</a>の記事を参照してください。</p> + +<h2 id="Test_your_skills!" name="Test_your_skills!">あなたのスキルをテストしてみましょう!</h2> + +<p>この記事はここまでですが、最も重要な情報を覚えていますか?先に進む前に、この情報を保持しているかどうかを確認するためのテストがいくつかあります - <a href="/en-US/docs/Learn/JavaScript/Objects/Test_your_skills:_Object-oriented_JavaScript">あなたのスキルをテストする: オブジェクト指向 JavaScript</a> を参照してください。</p> + +<h2 id="Summary" name="Summary">まとめ</h2> + +<p>この記事は今知っておくべき考えられる OOJS の核となる理論および文法の残りの部分をカバーしています。この時点で、 JavaScript オブジェクトおよび オブジェクト指向プログラミングの基本、プロトタイプとプロトタイプにおける継承、クラス(コンストラクタ)とオブジェクトのインスタンスの生成、クラスへの機能の追加、他のクラスから継承されたサブクラスの生成をどのように行うか、を理解しているでしょう。</p> + +<p>次の記事では JavaScript Object Notaion (JSON) 、つまり JavaScript オブジェクトを使用して書かれた共通データ交換フォーマット、がどのように動作するかをを見て行きましょう。</p> + +<h2 id="See_also" name="See_also">あわせて参照</h2> + +<ul> + <li><a href="http://www.objectplayground.com/">ObjectPlayground.com</a> — オブジェクトについて学べる非常に有益な会話型学習サイト</li> + <li><a href="https://www.amazon.com/gp/product/193398869X/">Secrets of the JavaScript Ninja</a>, Chapter 6 — John Resig Bear Bibeault による、先進的な JavaScript のコンセプトおよび手法についての良書。6 章ではプロトタイプや継承の非常に有効な面が説明されている。多分プリントやオンラインのコピーを比較的簡単に追跡する事ができるでしょう。</li> + <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes">You Don't Know JS: this & Object Prototypes</a> — Kyle Simpson による JavaScript を説明したすぐれたシリーズの一部。特に 5 章はプロトタイプについて、我々の説明より相当詳細に説明しています。初心者向けのこのシリーズ記事では単純化した見方を提供してきましたが、いっぽう Kyle は非常に深く論じており、より複雑だがより正確な図を提供しています。</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/json/index.html b/files/ja/learn/javascript/objects/json/index.html new file mode 100644 index 0000000000..c72a38744b --- /dev/null +++ b/files/ja/learn/javascript/objects/json/index.html @@ -0,0 +1,357 @@ +--- +title: JSON データの操作 +slug: Learn/JavaScript/Objects/JSON +tags: + - Article + - Beginner + - CodingScripting + - Guide + - JSON + - JavaScript + - Learn + - Objects + - Tutorial + - 'l10n:priority' +translation_of: Learn/JavaScript/Objects/JSON +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">JavaScript Object Notation (JSON) は表現用の標準的なテキストベースの構造データ表現フォーマットで、JavaScript 構造データオブジェクトの表記法をベースとしています。一般的にはウェブアプリケーションでデータを転送する場合に使われます。(例えば、データをサーバーからクライアントへ送信する場合などで、ウェブページに表示されたりすることもあり、その逆もあります)。頻繁に見かけるデータフォーマットですので、この節では JavaScript を使って JSON をパースする、JSON のデータを参照する、JSON を作るなど、JSON を扱うために必要となる操作を説明します。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>基礎的なコンピュータの知識、HTML と CSS への基本的な理解、基礎的な JavaScript の理解 (<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a>と <a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks">JavaScript の構成要素</a>を参照) とオブジェクト指向JavaScript の基本 (<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks">JavaScript オブジェクトの基本</a>を参照)。</td> + </tr> + <tr> + <th scope="row">目的:</th> + <td>JSON内のデータの扱い方、JSON 文字列の作成方法について理解できること。</td> + </tr> + </tbody> +</table> + +<h2 id="No_really_what_is_JSON" name="No_really_what_is_JSON">JSON とは何か</h2> + +<p>{{glossary("JSON")}} は JavaScript オブジェクトの構文に従ったテキストベースのフォーマットで、<a href="https://en.wikipedia.org/wiki/Douglas_Crockford">Douglas Crockford</a> によって普及されました。JSON は JavaScript オブジェクトの構文に似ていますが、JavaScript とは独立して扱われることがあり、多くのプログラミング言語環境には JSON を読み込む(パースする)したり生成したりする機能があります。</p> + +<p>JSON は文字列です。ですので、ネットワークを通してデータを転送したい場合に便利です。JSON データへアクセスしたい場合は、JavaScript オブジェクトへ変換する必要があります。JavaScript には JSON と JavaScript オブジェクトを相互に変換できるメソッドを持った <a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> というグローバルなオブジェクトがあるので、その変換は大きな問題ではありません。</p> + +<div class="note"> +<p><strong>注記</strong>: 文字列をネイティブオブジェクトへ変換することは<em>デシリアライゼーション (deserialization)</em> と呼ばれており、ネイティブオブジェクトをネットワークを通して転送できように文字列へ変換することは<em>シリアライゼーション (serialization) </em>と呼ばれています。</p> +</div> + +<p>JSON 文字列はそれ自身をファイルとして格納することもできます。それは {{glossary("MIME type")}} が <code>application/json</code> で、<code>.json</code> という拡張子の付いたただのテキストファイルです。</p> + +<h3 id="JSON_structure" name="JSON_structure">JSON の構造</h3> + +<p>上で説明したように、JSON は JavaScript オブジェクトにとても似ているフォーマットを持った文字列です。JSON では通常の JavaScript オブジェクトと同様な基本データ型(文字列、数値、配列、ブーリアンやその他のリテラル型)を使うことができます。これにより、以下のように階層的にデータを構成することができます。</p> + +<pre class="brush: json notranslate">'{ + "squadName": "Super hero squad", + "homeTown": "Metro City", + "formed": 2016, + "secretBase": "Super tower", + "active": true, + "members": [ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + }, + { + "name": "Eternal Flame", + "age": 1000000, + "secretIdentity": "Unknown", + "powers": [ + "Immortality", + "Heat Immunity", + "Inferno", + "Teleportation", + "Interdimensional travel" + ] + } + ] +}'</pre> + +<p>もし、この文字列を JavaScript プログラムへ読み込んだ場合(例えば、例えば変数<code>superHeroes</code> へ代入する)、<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a>の節で見たのと同様に ドットや角括弧を使ってデータへアクセスすることができます。例としては以下のようになります。</p> + +<pre class="brush: js notranslate">superHeroes.homeTown +superHeroes['active']</pre> + +<p>さらに深い階層のデータへアクセスする場合は、単純にプロパティ名や配列のインデックスを連結します。例えば、メンバーリスト中2番目のヒーローの 3番目の能力を参照する場合は、以下のようになります。</p> + +<pre class="brush: js notranslate">superHeroes['members'][1]['powers'][2]</pre> + +<ol> + <li>まず、変数名<code>superHeroes</code> を指定します。</li> + <li>その中の <code>members</code> プロパティへアクセスしたいので、<code>["members"]</code>と指定します。</li> + <li><code>members</code> にはオブジェクトの配列が格納されています. ここでは、配列内の 2番目のオブジェクトへアクセスするので、<code>[1]</code>を指定します。</li> + <li>そのオブジェクト内で、<code>powers</code> プロパティへアクセスするため, <code>["powers"]</code>と指定します。</li> + <li><code>powers</code> プロパティは選択したヒーローの能力を含んだ配列となっており、その中の 3番目が欲しいので、<code>[2]</code>と記述します。</li> +</ol> + +<div class="note"> +<p><strong>注記</strong>: 上記の JSON は <a href="http://mdn.github.io/learning-area/javascript/oojs/json/JSONTest.html">JSONTest.html</a> で参照することができます。(ページ内の <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/JSONTest.html">source code</a> を参照してください)。ページを読み込んで見て、ブラウザーのコンソールで変数内のデータにアクセスしてみてください。</p> +</div> + +<h3 id="Arrays_as_JSON" name="Arrays_as_JSON">JSON 配列</h3> + +<p>上記で、JSON テキストは基本的に文字列に入った JavaScript オブジェクトのように見えることを説明しました。配列を JSON との間で変換することもできます。以下も有効な JSON です。例:</p> + +<pre class="brush: json notranslate">'[ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + } +]'</pre> + +<p>これも有効な JSON であり、パースしたデータには配列のインデックスを指定するだけです。例えば、<code>[0]["powers"][0]</code>のように表記できます。</p> + +<h3 id="Other_notes" name="Other_notes">その他の注意点</h3> + +<ul> + <li>JSON は指定されたデータフォーマットの純粋な文字列であり、プロパティのみを含むことができ、メソッドを含むことができません。</li> + <li>JSON では文字列とプロパティ名をダブルクォートで括る必要があります。シングルクォートは、JSON 文字列全体を囲む以外では無効です。</li> + <li>1 つだけカンマやコロンが抜けているだけで無効な JSON になりえます。なので、使用しているデータが有効であるかについては注意してみなければなりません(機械的に作った JSON のほうが、プログラムに問題がなければ、エラーは少なく済みます)。 <a href="http://jsonlint.com/">JSONLint</a> のようなアプリケーションを使って妥当性検査をすることもできます。</li> + <li>JSON は配列やオブジェクトに限らず JSON内に含むことができるデータ型のデータだけでも有効な JSON となります。 例えば、1 つだけの文字列や数値も有効な JSON です。</li> + <li>プロパティがクォートで括られていない JavaScript コードと異なり、JSON では、クォートされた文字列だけがプロパティとして使われます。</li> +</ul> + +<h2 id="Active_learning_Working_through_a_JSON_example" name="Active_learning_Working_through_a_JSON_example">手を動かして学ぼう: JSON をさわってみる</h2> + +<p>それでは、Web サイト上でどのように JSON 形式のデータを使うことができるか例を通して見てみましょう。</p> + +<h3 id="Getting_started" name="Getting_started">はじめに</h3> + +<p>まず、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes.html">heroes.html</a> と <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/style.css">style.css</a> のコピーをローカルに作成してください。後者は例題ページをスタイリングするための CSS であり、前者は簡単な形式の HTML です。</p> + +<pre class="brush: html notranslate"><header> +</header> + +<section> +</section></pre> + +<p>他には、この演習で書く JavaScript を含んだ {{HTMLElement("script")}} 要素があります。この時点では、{{HTMLElement("header")}} 要素と {{HTMLElement("section")}} 要素 を取得して、変数へ代入している 2行コードのみが書かれています。</p> + +<pre class="brush: js notranslate">const header = document.querySelector('header'); +const section = document.querySelector('section');</pre> + +<p>演習用の JSON データは <a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json</a> に用意してあります。</p> + +<p>そのデータを演習ページに読み込んで、それを表示するのにいくらかの DOM操作を行います。最終的には、以下の画像のようになります。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13857/json-superheroes.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="Obtaining_the_JSON" name="Obtaining_the_JSON">JSON の取得</h3> + +<p>JSON を取得するには、{{domxref("XMLHttpRequest")}} (しばしば <strong>XHR</strong> と呼ばれる) という API を使用します。これは非常に便利な JavaScript オブジェクトで、JavaScript を使用してサーバからリソース (例:画像、テキスト、JSON、さらには HTML スニペットなど) を取得するネットワークリクエストを行うことができます。つまりページ全体を再読み込みせずに、小さな部分のコンテンツを更新することができます。これにより、よりレスポンシブな Web ページを作成できますが、それをもっと詳細に教えるのはこの記事の範囲を超えています。</p> + +<ol> + <li>まず、取得したい JSON がある URL を変数へ代入します。次のコードを JavaScript の最後の行へ追加してください。 + <pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">let</span> requestURL <span class="operator token">=</span> <span class="string token">'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json'</span><span class="punctuation token">;</span></code></pre> + </li> + <li>HTTP リクエストを作成するのに、<code>new</code> を使って <code>XMLHttpRequest</code> から新しいリクエストオブジェクトをつくる必要があります。先ほどのコードの下に、次のコードを追加してください。 + <pre class="brush: js notranslate">let request = new XMLHttpRequest();</pre> + </li> + <li>新しいリクエストを開始するのには <code><a href="/ja/docs/Web/API/XMLHttpRequest/open">open()</a></code> メソッドを使います。 次のコードを追加してください。 + <pre class="brush: js notranslate">request.open('GET', requestURL);</pre> + + <p>このメソッドは最低2つのパラメータを引数として取ります(他に任意の引数を与えることもできます)。今回の簡単な例では、次の2つの必須パラメータのみを利用します。</p> + + <ul> + <li>リクエストを開始する際に HTTP のメソッドを決める必要があります。今回のケースでは、単純にデータを取得するだけですので <code><a href="/ja/docs/Web/HTTP/Methods/GET">GET</a></code> が良いでしょう。</li> + <li>リクエストを送る先の URL。今回は JSON ファイルが置かれている URL です。</li> + </ul> + </li> + <li>次に、以下の2行のコードを追加してください。XHR オブジェクトがサーバーから返されるデータを判断できるように <code><a href="/ja/docs/Web/API/XMLHttpRequest/responseType">responseType</a></code> に JSON を指定します。すると、ブラウザ側で JavaScript オブジェクトへ変換してくれます。それから、<code><a href="/ja/docs/Web/API/XMLHttpRequest/send">send()</a></code> メソッドでリクエストを送信します。 + <pre class="brush: js notranslate">request.responseType = 'json'; +request.send();</pre> + </li> + <li>最後に、サーバーからのレスポンスを待ち、それを処理するコードを用意するので、以下のコードをこれまでのコードの下に追加してください。 + <pre class="brush: js notranslate">request.onload = function() { + const superHeroes = request.response; + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + </li> +</ol> + +<p>ここでは、先ほどのリクエストに対するレスポンス (<code><a href="/ja/docs/Web/API/XMLHttpRequest/response">response</a></code> プロパティから取得できます) を <code>superHeroes</code> という変数へ代入しています。つまり、この変数に JSON を元に生成された JavaScript オブジェクトが格納されているということです! それから 2 つの関数をそのオブジェクトを引数として与えて呼び出しています。最初の関数は引数のデータを <code><header></code> へ埋め込み、2 つ目は各ヒーローごとのインフォメーションカードを作り、<code><section></code> へ埋め込みます。</p> + +<p>上記の処理は、リクエストオブジェクトで load イベントが発生した時に呼び出される関数 (<code><a href="/ja/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> を参照) に記述しました。このイベントはレスポンスがうまく取得できた場合に呼び出されるので、 <code>request.response</code> を使って何か処理をしようとしたときに、それが必ず利用できることが保証されています。</p> + +<h3 id="Populating_the_header" name="Populating_the_header">ヘッダーへの値のセット</h3> + +<p>ここまでで、JSON の取得と JavaScript オブジェクトへの変換ができました、先ほどの 2 つの関数を実装して使ってみましょう。まずはじめに、以下のコードをこれまでのコードの下に追加してください。</p> + +<pre class="brush: js notranslate">function populateHeader(obj) { + const myH1 = document.createElement('h1'); + myH1.textContent = obj['squadName']; + header.appendChild(myH1); + + const myPara = document.createElement('p'); + myPara.textContent = 'Hometown: ' + obj['homeTown'] + ' // Formed: ' + obj['formed']; + header.appendChild(myPara); +}</pre> + +<p>まず、<code><a href="/ja/docs/Web/API/Document/createElement">createElement()</a></code> で {{HTMLElement("h1")}} 要素を生成、その <code><a href="/ja/docs/Web/API/Node/textContent">textContent</a></code> プロパティにそのオブジェクトの <code>squadName</code> プロパティをセット、そしてそれを <code><a href="/ja/docs/Web/API/Node/appendChild">appendChild()</a></code> を使いヘッダーに追加します。そして要素の生成、テキストのセット、ヘッダーへの追加という同じような操作をパラグラフ要素でも行います。セットするテキストの値が <code>homeTown</code> と <code>formed</code> プロパティの文字列を結合したものであるという点だけが異なります。</p> + +<h3 id="Creating_the_hero_information_cards" name="Creating_the_hero_information_cards">ヒーローインフォメーションカードの作成</h3> + +<p>次に、以下の関数をコードの下へ追記してください。この関数はスーパーヒーローカードの作成と画面表示を行います。</p> + +<pre class="brush: js notranslate">function showHeroes(jsonObj) { + const heroes = jsonObj['members']; + + for (let i = 0; i < heroes.length; i++) { + const myArticle = document.createElement('article'); + const myH2 = document.createElement('h2'); + const myPara1 = document.createElement('p'); + const myPara2 = document.createElement('p'); + const myPara3 = document.createElement('p'); + const myList = document.createElement('ul'); + + myH2.textContent = heroes[i].name; + myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity; + myPara2.textContent = 'Age: ' + heroes[i].age; + myPara3.textContent = 'Superpowers:'; + + const superPowers = heroes[i].powers; + for (let j = 0; j < superPowers.length; j++) { + const listItem = document.createElement('li'); + listItem.textContent = superPowers[j]; + myList.appendChild(listItem); + } + + myArticle.appendChild(myH2); + myArticle.appendChild(myPara1); + myArticle.appendChild(myPara2); + myArticle.appendChild(myPara3); + myArticle.appendChild(myList); + + section.appendChild(myArticle); + } +}</pre> + +<p>始めに、JavaScript オブジェクトの <code>members</code> プロパティを新しい変数に保存します。<br> + この配列は複数のオブジェクトを持ち、オブジェクトはそれぞれのヒーローについての情報を持ちます。</p> + +<p>次に、<a href="/ja/docs/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">for ループ</a>を使って配列の個々のオブジェクトについてループしていきます。それぞれについて:</p> + +<ol> + <li>新しい要素をいくつか作ります: <code><article></code> 1つ、<code><h2></code> 1つ、3つの <code><p></code> と1つの <code><ul></code> です。</li> + <li><code><h2></code> の中身を今のヒーローの名前 (<code>name</code>) にします。</li> + <li>3つの <code><p></code> の中身を、それぞれの <code>secretIdentity</code> と <code>age</code>、リストにある情報を紹介していくために「超能力 ("Superpowers:")」で始まる行とします。</li> + <li><code>powers</code> プロパティを <code>superPowers</code> という新しい定数に保存します — この定数は今のヒーローの超能力のリストを持つ配列です。</li> + <li>別の <code>for</code> ループをつかって、今のヒーローの超能力をループします — それぞれに対する <code><li></code> 要素を作成し、超能力をこの要素の中身とし、<code><ul></code>要素(<code>myList</code>変数)の <code>listItem</code> に <code>appendChild()</code> を使って追加します。</li> + <li>最後の最後にやるのは、<code><h2></code>、<code><p></code>、<code><ul></code> を <code><article></code> (<code>myArticle</code>) の中身に追加し、それから <code><article></code> を <code><section></code> の中身に追加します。HTML の中身として表示される順序になりますので、これらの要素が追加された順序は重要です。</li> +</ol> + +<div class="note"> +<p><strong>付記</strong>: 例を動かしてみるのに問題があったら、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished.html">heroes-finished.html</a> ソースコードを参照して見て下さい(こちらで <a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished.html">ライブ実行</a> もできます)。</p> +</div> + +<div class="note"> +<p><strong>付記</strong>: もし JavaScript オブジェクトにアクセスするのに使っているドット/ブラケット記法をなぞっていくのが難しければ、<a href="http://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">superheroes.json</a> のファイルを別のタブやテキストエディタで開いておいて、JavaScript と並べて読んでいくとわかりやすいかもしれません。<a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a> 記事にも戻って、ドット/ブラケット記法について読み返してみてください。</p> +</div> + +<h2 id="Converting_between_objects_and_text" name="Converting_between_objects_and_text">オブジェクトとテキスト間の変換</h2> + +<p>上の例は XHR リクエストで JSON レスポンスを直接JavaScript オブジェクトに変換していたので、JavaScript オブジェクトへのアクセスという面では単純でした。次の部分です:</p> + +<pre class="brush: js notranslate">request.responseType = 'json';</pre> + +<p>時にはこんなにツイていない場合もあります — 時には生の JSON 文字列を受けとり、自分でオブジェクトに変換しなければならない場合もあるでしょう。また JavaScript オブジェクトをネットワーク越しに送信したい場合、送信する前に JSON 文字列に変換しなければならないでしょう。ツイている事に、ウェブ開発でこの二つの問題にはしょっちゅう出くわすので、ブラウザには組込みの <a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> オブジェクトが備わっていて、これは以下二つのメソッドを備えています:</p> + +<ul> + <li><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">parse()</a></code>: JSON文字列を引数に取り、それに対する JavaScript オブジェクトを返します。</li> + <li><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">stringify()</a></code>: オブジェクトを引数に取り、等価な JSON 文字列を返します。</li> +</ul> + +<p>一つめの方の動作例が <a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished-json-parse.html">heroes-finished-json-parse.html</a> にあります (<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished-json-parse.html">ソース</a> を見て下さい) — ここでは前の方で作成した例と全く同じ事をしていますが、XHR では生の JSON 文字列を返させて、それを <code>parse()</code> で JavaScript オブジェクトに変換しているところだけが異なります。コードの重要な箇所はこの部分です:</p> + +<pre class="brush: js notranslate">request.open('GET', requestURL); +request.responseType = 'text'; // now we're getting a string! +request.send(); + +request.onload = function() { + const superHeroesText = request.response; // get the string from the response + const superHeroes = JSON.parse(superHeroesText); // convert it to an object + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + +<p>で、ご想像の通り <code>stringify()</code> は全く反対の向きに動作します。次の行をブラウザーの JavaScript コンソールに一つずつ打ち込んでいって、実際に動かしてみて下さい:</p> + +<pre class="brush: js notranslate">let myObj = { name: "Chris", age: 38 }; +myObj +let myString = JSON.stringify(myObj); +myString</pre> + +<p>JavaScript オブジェクトを作成してその中身を確認し、次に <code>stringify()</code> を使って JSON 文字列に変換し — 戻り値を新しい変数に保存しています — その値も確認しています。</p> + +<h2 id="Test_your_skills!" name="Test_your_skills!">あなたのスキルをテストしてみましょう!</h2> + +<p>この記事はここまでですが、最も重要な情報を覚えていますか?先に進む前に、この情報を保持しているかどうかを確認するためのテストがいくつかあります — <a href="/ja/docs/Learn/JavaScript/Objects/Test_your_skills:_JSON">Test your skills: JSON</a> を参照してください。</p> + +<h2 id="Summary" name="Summary">まとめ</h2> + +<p>この節では、プログラム内で、JSON を生成する、JSON をパースする、JSON データを参照するなど、JSON を扱う方法について簡単に説明しました。次の節では、オブジェクト指向 JavaScript について見ていくことにします。</p> + +<h2 id="See_also" name="See_also">あわせて参照</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON リファレンス</a></li> + <li><a href="https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest">XMLHttpRequest オブジェクトリファレンス</a></li> + <li><a href="https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest">XMLHttpRequest の利用</a></li> + <li><a href="https://developer.mozilla.org/ja/docs/Web/HTTP/Methods">HTTP リクエストメソッド</a></li> + <li><a href="http://json.org/">ECMA のオフィシャル JSON Web サイト</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/object-oriented_js/index.html b/files/ja/learn/javascript/objects/object-oriented_js/index.html new file mode 100644 index 0000000000..ab99282acb --- /dev/null +++ b/files/ja/learn/javascript/objects/object-oriented_js/index.html @@ -0,0 +1,291 @@ +--- +title: 初心者のためのオブジェクト指向 JavaScript +slug: Learn/JavaScript/Objects/Object-oriented_JS +tags: + - Beginner + - Create + - JavaScript + - OOJS + - OOP + - オブジェクト + - オブジェクト指向 + - 学習 + - 記事 +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">基礎が片付いたところで、オブジェクト指向 JavaScript (OOJS) について取り上げます。この記事ではオブジェクト指向プログラミング (OOP) の基本的な視点を説明し、 JavaScript がどのようにコンストラクター関数を通じてオブジェクトクラスをエミュレートしているか、またどのようにオブジェクトインスタンスを生成しているかを紹介します。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提知識:</th> + <td>基礎的なコンピュータリテラシー、基礎的な HTML と CSS の理解、JavaScript (<a href="/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a>や <a href="/ja/docs/Learn/JavaScript/Building_blocks">JavaScript の構成要素</a>を参照) および OOJS (<a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a>を参照)の基礎知識。</td> + </tr> + <tr> + <th scope="row">目標:</th> + <td>オブジェクト指向プログラミングの基本理論、どのようにそれが JavaScript (「すべてはオブジェクトである」) に関連しているか、どのようにコンストラクターがオブジェクトインスタンスを生成しているかを理解する。</td> + </tr> + </tbody> +</table> + +<h2 id="Object-oriented_programming_—_the_basics" name="Object-oriented_programming_—_the_basics">オブジェクト指向プログラミング - その基本</h2> + +<p>はじめに、オブジェクト指向プログラミング (OOP) とは何か、シンプルかつ高レベルな視点を提示します。シンプルと述べたのは、OOP はあっという間にひどく複雑になり得るためで、現時点でそのすべてを論じてしまうと、助けとなるよりもむしろ混乱を生んでしまうことでしょう。OOP の基本的な考え方は、プログラムの中で扱いたい、現実世界の事物を模るためにオブジェクトを使用すること、またはそうしなければ使うことが難しいあるいは不可能だった機能にアクセスするための、シンプルな方法を提供することです。</p> + +<p>オブジェクトは、モデル化しようとしている事物に関する情報および、持たせたい機能や動作を表現する、関連したデータとコードを持つことができます。オブジェクトのデータ (しばしば関数も含む) はオブジェクトのパッケージの中 (<strong>名前空間</strong>と呼ばれることがある) に適切に格納されます (<strong>カプセル化</strong>)。オブジェクトは一般に、ネットワークを通じて容易に送信することが可能な、データストアとしても使われます。</p> + +<h3 id="Defining_an_object_template" name="Defining_an_object_template">オブジェクトのテンプレートを定義する</h3> + +<p>学校の生徒と教師の情報を表示する、シンプルなプログラムを考えてみましょう。特定のプログラミング言語の文脈ではなく、OOP 一般の理論を眺めていきます。</p> + +<p>はじめに、<a href="/ja/docs/Learn/JavaScript/Objects/Basics">オブジェクト入門の最初の記事</a>にある、人物の包括的なデータや機能を定義した、Person オブジェクトに戻りましょう。ある人物について知り得る事柄は数多くあります (住所、身長、靴のサイズ、DNA 情報、パスポート番号、顕著な人格特性など) が、このケースでは名前、年齢、性別、趣味を表示することに興味があるだけです。また、このデータに基づいた短い自己紹介や、挨拶をさせられるようにもしましょう。これは<strong>抽象化</strong> — より複雑な事物を、プログラムの目的に沿って簡単に操作できるように、その最も重要な側面を表現する、シンプルなモデルを作ること — として知られています。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13889/person-diagram.png" style="display: block; height: 219px; margin: 0px auto; width: 610px;"></p> + +<h3 id="Creating_actual_objects" name="Creating_actual_objects">実際のオブジェクトの生成</h3> + +<p>このクラスから、<strong>オブジェクトインスタンス</strong>を生成することができます。オブジェクトインスタンスは、クラスで定義されたデータや機能を持ったオブジェクトです。 Person クラスから、何名かの実際の人物を生成します。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15163/MDN-Graphics-instantiation-2-fixed.png" style="display: block; height: 702px; margin: 0px auto; width: 695px;"></p> + +<p>クラスからオブジェクトインスタンスが生成されるとき、クラスの<strong>コンストラクター関数</strong>が生成のために実行されます。クラスからオブジェクトインスタンスが生成される過程を<strong>インスタンス化</strong>と呼びます。オブジェクトインスタンスは、クラスを<strong>インスタンス化</strong>したものです。</p> + +<h3 id="Specialist_classes" name="Specialist_classes">専門のクラス</h3> + +<p>このケースで求めているのは、包括的な人物ではなく、より特定のタイプである、教師と生徒です。OOP では、他のクラスを元にした新しいクラスを作ることができます。これらの新しい<strong>子クラス</strong>は、<strong>親クラス</strong>からデータやコード機能を<strong>継承</strong>することができ、すべてのオブジェクトタイプに共通する機能を、重複させるのではなく、再利用することができます。クラス間で機能が異なる場合は、必要に応じて特殊化された機能を直接定義することができます。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13881/MDN-Graphics-inherited-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>これは実に役立ちます。教師と生徒は名前、性別、年齢のように多数の共通機能を共有しており、これらの機能を一度だけ定義すればいいので便利です。異なるクラスで、同じ機能を分けて定義することもでき、その機能の各定義は異なる名前空間に置かれます。例えば、生徒の挨拶は "Yo, I'm [firstName]" (例:<em>Yo, I'm Sam) という形式とし、一方の教師の挨拶は、より形式的に </em>"Hello, my name is [Prefix] [lastName], and I teach [Subject]." (例:<em>Hello, My name is Mr Griffiths, and I teach Chemistry) のように。</em></p> + +<div class="note"> +<p><strong>注</strong>: 同じ機能を複数のオブジェクトタイプが実装する能力のことを示す用語に、<strong>ポリモーフィズム</strong>があります。不思議に感じているかも知れないので念のため。</p> +</div> + +<p>子クラスのオブジェクトインスタンスを生成しましょう。例:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13885/MDN-Graphics-instantiation-teacher-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>記事の続きでは、OOP 理論が JavaScript でどのように実践されているかを見ていきます。</p> + +<h2 id="Constructors_and_object_instances" name="Constructors_and_object_instances">コンストラクターとオブジェクトインスタンス</h2> + +<p>JavaScript では、オブジェクトやその機能を定義し初期化するために<strong>コンストラクター関数</strong>と呼ばれる特殊な関数を使用します。これは便利です。なぜならオブジェクトをいくつ作成することになるか分からない状況に出くわすでしょうから。コンストラクターは必要な数のオブジェクトを効率的な方法で作成し、必要に応じてデータや関数を付加する手段を提供します。</p> + +<p>JavaScript でコンストラクターを通じてクラスを作り、そこからオブジェクトのインスタンスを生成するところを見ていきましょう。まずは、最初のオブジェクトの記事で見た <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> ファイルの新しいコピーを、ローカルに作成したおいてください。</p> + +<h3 id="A_simple_example" name="A_simple_example">シンプルな例</h3> + +<ol> + <li>どのように通常の関数で人物を定義できるかを見てみるところから始めましょう。この関数を <code>script</code> 要素の中に加えてください。 + + <pre class="brush: js notranslate">function createNewPerson(name) { + const obj = {}; + obj.name = name; + obj.greeting = function() { + alert('Hi! I\'m ' + obj.name + '.'); + }; + return obj; +}</pre> + </li> + <li>この関数を呼び出すことで、新しい人物を生成することができます。次の 3 行をブラウザーの JavaScript コンソールで試してみてください。 + <pre class="brush: js notranslate">const salva = createNewPerson('Salva'); +salva.name; +salva.greeting();</pre> + これも十分上手くいっていますが、やや長ったらしいです。オブジェクトを生成したいと知っているなら、なぜ明示的に空のオブジェクトを生成し、返すことが必要なのでしょうか?幸いにも、 JavaScript はコンストラクター関数という形で、便利なショートカットを提供してくれます。早速作ってみましょう!</li> + <li>前の関数を、以下のもので置き換えてください。 + <pre class="brush: js notranslate">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + </li> +</ol> + +<p>コンストラクター関数は、 JavaScript 版のクラスです。それは関数に期待される全ての機能を持っていますが、何も返さないし、明示的にオブジェクトを生成しもしないという点に注意してください。基本的には、プロパティとメソッドを定義するだけです。加えて、 <code>this</code> キーワードが使われていることにも注意してください。基本、オブジェクトインスタンスの 1 つが作成されるときにはいつでも、オブジェクトの <code>name</code> プロパティはコンストラクター呼び出しに渡される name 値と等しくなり、 <code>greeting()</code> メソッドもコンストラクター呼び出しに渡される name 値を使用します。</p> + +<div class="note"> +<p><strong>メモ</strong>: 通常、コンストラクター関数の名前は大文字で始まります。コードの中で、コンストラクター関数がより容易に認識されるようにするための慣習です。</p> +</div> + +<p>では、オブジェクトを生成するために、どのようにコンストラクターを呼び出したらよいでしょうか?</p> + +<ol> + <li>次の 2 行を、前のコードの続きに加えてください。 + <pre class="brush: js notranslate">let person1 = new Person('Bob'); +let person2 = new Person('Sarah');</pre> + </li> + <li>コードを保存し、ブラウザーをリロードして、以下の 4 行を JavaScript コンソールに入れて試してみてください。 + <pre class="brush: js notranslate">person1.name +person1.greeting() +person2.name +person2.greeting()</pre> + </li> +</ol> + +<p>素晴らしい!2 つの新しいオブジェクトが、異なる名前空間の下でページに格納されていることが確認できます。それらのプロパティとメソッドにアクセスするときには、 <code>person1</code> または <code>person2</code> を呼び出すことから始めなければなりません。中に含まれている機能は適切にパッケージ化されており、他の機能と衝突しないようになっています。しかしながら、それらは同じように <code>name</code> プロパティと <code>greeting()</code> メソッドが利用可能です。 2 つのオブジェクトはそれぞれ、生成されたときに割り当てられた、自身の <code>name</code> 値を使っていることに注意してください。これが <code>this</code> を使うことがとても重要である理由の 1 つであり、他の値ではなく、自身の値を使っているのです。</p> + +<p>コンストラクターをもう一度呼び出してみましょう。</p> + +<pre class="brush: js notranslate">let person1 = new Person('Bob'); +let person2 = new Person('Sarah');</pre> + +<p>いずれのケースでも、新しいオブジェクトインスタンスを生成したいとブラウザーに伝えるために <code>new</code> キーワードが使われており、その後に、括弧に必要なパラメーターを入れた関数名が続き、その結果が変数に格納されていて、一般的な関数の呼ばれ方とよく似ています。どちらのインスタンスも、次の定義によって生成されています。</p> + +<pre class="brush: js notranslate">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + +<p>新しいオブジェクトが生成された後、 <code>person1</code> および <code>person2</code> 変数は、次のオブジェクトを格納しています。</p> + +<pre class="brush: js notranslate">{ + name: 'Bob', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +{ + name: 'Sarah', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>コンストラクター関数を呼び出すとき、毎回 <code>greeting()</code> メソッドを定義していることに注意してください。これは理想的ではありません。これを回避するために、代わりにプロトタイプに関数を定義することができます。後で見てみましょう。</p> + +<h3 id="Creating_our_finished_constructor" name="Creating_our_finished_constructor">最終的なコンストラクターの作成</h3> + +<p>上で見てきた例は、スタートのためのシンプルな例に過ぎません。次は最終的な <code>Person()</code> コンストラクター関数を作りましょう。</p> + +<ol> + <li>ここまでに挿入したコードを削除し、代わりとなるコンストラクターを追加してください。これはシンプルな例とほぼ同じもので、ほんのわずか複雑になっているだけです。 + <pre class="brush: js notranslate">function Person(first, last, age, gender, interests) { + this.name = { + first : first, + last : last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.bio = function() { + alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }; + this.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); + }; +}</pre> + </li> + <li>ではその下に、コンストラクターからオブジェクトインスタンスを生成するため、次の行を追加してください。 + <pre class="brush: js notranslate">let person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + </li> +</ol> + +<p>ちょうど以前行ったように、プロパティやメソッドにアクセスできることを確認できます。 JavaScript コンソールの中でやってみましょう。</p> + +<pre class="brush: js notranslate">person1['age'] +person1.interests[1] +person1.bio() +// etc.</pre> + +<div class="note"> +<p><strong>メモ</strong>: もしこの工程で何らかのトラブルがあった場合は、あなたのコードを我々のバージョン (<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-finished.html">oojs-class-finished.html</a>。<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-finished.html">ライブサンプル</a>も) と比べてみてください。</p> +</div> + +<h3 id="Further_exercises" name="Further_exercises">さらなる練習</h3> + +<p>まずはじめに、さらにいくつかのオブジェクトを生成する独自の行を追加し、オブジェクトインスタンスのメンバーの取得や設定をしてみてください。</p> + +<p>加えて、 <code>bio()</code> メソッドにはいくつかの問題点があります。人物が女性である、あるいは他の優先される性別分類の場合でも、その出力には常に "He" という代名詞が含まれています。また、 bio は <code>interests</code> 配列により多くのものが列挙されていても、2 つの趣味しか含みません。このクラス定義 (コンストラクター) の問題を、あなたはどのように修正することができますか?コンストラクター内に任意のコード (恐らく、いくつかの条件分岐やループが必要となるでしょう) を入れてみてください。性別や、趣味の数が 1、2、あるいは 2 よりも多いかどうかによって、文がどのように構築されるべきか考えてみてください。</p> + +<div class="note"> +<p><strong>注</strong>: もし行き詰まってしまった場合は、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">GitHub に答えとなるリポジトリ</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">ライブ</a>) があります。最初はあなた自身で書いてみてください!</p> +</div> + +<h2 id="Other_ways_to_create_object_instances" name="Other_ways_to_create_object_instances">オブジェクトインスタンスを生成する他の方法</h2> + +<p>ここまで、オブジェクトインスタンスを生成する 2 つの異なる方法を見てきました。<a href="/ja/docs/Learn/JavaScript/Objects/Basics#Object_basics">オブジェクトリテラルの宣言</a>と、上で見たコンストラクター関数の使用です。</p> + +<p>これで十分かもしれませんが、他にも方法はあります。ウェブを巡る際に遭遇したときに備えて、よく知っておいてください。</p> + +<h3 id="The_Object_constructor" name="The_Object_constructor">Object() コンストラクター</h3> + +<p>まず最初に、 <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object">Object()</a></code> コンストラクターを新しいオブジェクトの生成のために使うことができます。はい、一般的なオブジェクトにも、空のオブジェクトを生成するコンストラクターがあります。</p> + +<ol> + <li>このコードを JavaScript コンソールに入力してみましょう。 + <pre class="brush: js notranslate">let person1 = new Object();</pre> + </li> + <li><code>person1</code> 変数に空のオブジェクトが格納されました。このオブジェクトに、ドット記法とブラケット記法を使ってプロパティを追加することができます。次の例を JavaScript コンソールで試してみましょう。 + <pre class="brush: js notranslate">person1.name = 'Chris'; +person1['age'] = 38; +person1.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); +};</pre> + </li> + <li>あらかじめプロパティやメソッドを設定するため、<code>Object()</code> コンストラクターに引数としてオブジェクトリテラルを渡すことも可能です。次のコードを JavaScript コンソールで試してみてください。 + <pre class="brush: js notranslate">let person1 = new Object({ + name: 'Chris', + age: 38, + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +});</pre> + </li> +</ol> + +<h3 id="Using_the_create_method" name="Using_the_create_method">create() メソッドの使用</h3> + +<p>コードの順序についてもコンストラクターが助けとなります。コンストラクターを一箇所で作っておくと、必要に応じてインスタンスを生成することができ、それらがどこから来たものであるか、明瞭です。</p> + +<p>しかしながら、特に少数のインスタンスのみを生成する場合に、最初にコンストラクターを作らずにインスタンスを生成することを好む人もいます。JavaScript にはそれを可能とする、<code>create()</code> と呼ばれる組み込みメソッドがあります。それにより、既存のオブジェクトを基にして、新しいオブジェクトを生成することができます。</p> + +<ol> + <li>前のセクションの練習をブラウザーで終えた状態で、こちらを JavaScript コンソールで試してみてください。 + <pre class="brush: js notranslate">let person2 = Object.create(person1);</pre> + </li> + <li>次は以下のコードです。 + <pre class="brush: js notranslate">person2.name; +person2.greeting();</pre> + </li> +</ol> + +<p><code>person1</code> を基に <code>person2</code> が生成され、<code>person2</code> では同じプロパティとメソッドが利用可能であることを確認することができます。</p> + +<p><code>create()</code> には、IE8 が対応していないという制限があります。つまり、コンストラクターは古いブラウザーに対応したい場合により効果的かもしれません。</p> + +<p>いずれ、<code>create()</code> の効果についてより詳細に紹介するつもりです。</p> + +<h2 id="あなたのスキルをテストしてみましょう!">あなたのスキルをテストしてみましょう!</h2> + +<p>この記事はここまでですが、最も重要な情報を覚えていますか?先に進む前に、この情報を保持しているかどうかを確認するために、さらにいくつかのテストを見つけることができます。<a class="new" href="https://wiki.developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Test_your_skills:_Object-oriented_JavaScript" rel="nofollow">あなたのスキルをテストする: オブジェクト指向 JavaScript</a> を参照してください。</p> + +<p>この一連のテストは次の記事で紹介する知識に依存していることに注意してください。なので、試してみる前に、まずそれを読んでみるといいかもしれません。</p> + +<h2 id="Summary" name="Summary">まとめ</h2> + +<p>この記事はオブジェクト指向の理論の概略を見てきました。これですべてではありませんが、ここで扱っていることに関する考えを提示しました。加えて、オブジェクトのインスタンスを生成する様々な方法を見始めたところです。</p> + +<p>次の記事では、 JavaScript オブジェクトのプロトタイプについて紹介します。</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール内の文書</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/object_building_practice/index.html b/files/ja/learn/javascript/objects/object_building_practice/index.html new file mode 100644 index 0000000000..af94a8eede --- /dev/null +++ b/files/ja/learn/javascript/objects/object_building_practice/index.html @@ -0,0 +1,314 @@ +--- +title: オブジェクト構築の練習 +slug: Learn/JavaScript/Objects/Object_building_practice +tags: + - Article + - Beginner + - Canvas + - CodingScripting + - Guide + - JavaScript + - Learn + - Objects + - Tutorial + - 'l10n:priority' +translation_of: Learn/JavaScript/Objects/Object_building_practice +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">ここまでの記事で JavaScript オブジェクトの根幹部に関する理論と文法の詳細についてすべてを見てきて、始めていくのに十分な基礎固めをしました。この記事では実練習を行ない、独自の JavaScript オブジェクトを作っていくための実践をしていきましょう — 楽しくてカラフルなものを。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>基礎的なコンピューターの知識、HTML と CSS への基本的な理解、基礎的な JavaScript の理解 (<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a>と <a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks">JavaScript の構成要素</a>を参照) とオブジェクト指向JavaScript の基本 (<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks">JavaScript オブジェクトの基本</a>を参照)。</td> + </tr> + <tr> + <th scope="row">目的:</th> + <td>オブジェクトの使い方とオブジェクト指向のテクニックを実世界のコンテストで練習する。</td> + </tr> + </tbody> +</table> + +<h2 id="Lets_bounce_some_balls" name="Lets_bounce_some_balls">ボールを弾ませよう</h2> + +<p>この記事では伝統的な「弾むボール」のデモを作ってみて、JavaScript でどれほどオブジェクトが役に立つかお見せしましょう。小さなボールは画面じゅうを跳ねまわり、それぞれがぶつかると色が変わります。完成したものはこんな風に見えることでしょう:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13865/bouncing-balls.png" style="display: block; height: 614px; margin: 0px auto; width: 800px;"></p> + +<ol> +</ol> + +<p>この例では画面にボールを描くのに <a href="/ja/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Canvas API</a> を使い、画面をアニメーションさせるのに <a href="/ja/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a> を使います — これらの API について事前の知識は不要です。この記事を読み終わる頃にはこれら API についてもっと知りたくなっているだろうと期待してますが。道中では、イカしたオブジェクトを活用して、ボールを壁で弾ませる、それぞれがぶつかった事を判定する(<strong>衝突判定</strong>という呼び名で知られています)といった上手いテクニックをいくつかお見せしていきます。</p> + +<h2 id="Getting_started" name="Getting_started">始めに</h2> + +<p>始める前に <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/index.html">index.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/style.css">style.css</a></code>, と <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main.js">main.js</a></code> ファイルのローカルコピーを作成してください。これらにはそれぞれ、以下が含まれています:</p> + +<ol> + <li>とても簡素な HTML文書で、{{HTMLElement("h1")}} 要素と、ボールを描画するための {{HTMLElement("canvas")}} 要素と、この HTML に CSS と JavaScript を適用するための要素だけからなります。</li> + <li>とても簡単なスタイル、主には<code><h1></code>のスタイルとポジションを指定し、スクロールバーやページ端周辺のマージンを消す(素敵にきれいに見せるため)ためのもの。</li> + <li><code><canvas></code>要素を設定し、これから使うことになる汎用の関数を提供する若干の JavaScript。</li> +</ol> + +<p>スクリプトの最初の部分はこんな具合です:</p> + +<pre class="brush: js notranslate">const canvas = document.querySelector('canvas'); + +const ctx = canvas.getContext('2d'); + +const width = canvas.width = window.innerWidth; +const height = canvas.height = window.innerHeight;</pre> + +<p>このスクリプトでは<code><canvas></code>要素への参照を取得し、これに対して <code><a href="/ja/docs/Web/API/HTMLCanvasElement/getContext">getContext()</a></code> メソッドを使って描画していくためのコンテキストを取得します。得られる定数 (<code>ctx</code>) はキャンバスの描画可能領域を直接表現しており、ここに二次元の形状を書き込む事ができます。</p> + +<p>次に <code>width</code> と <code>height</code> 二つの定数をセットし、キャンバス要素の幅と高さ(<code>canvas.width</code> と <code>canvas.height</code> プロパティで表わされます)をブラウザーのビューポートの幅と高さ(ウェブページが表示される領域です — {{domxref("Window.innerWidth")}} と{{domxref("Window.innerHeight")}} プロパティから取得できます)に等しくします。</p> + +<p>変数値をさっと全部同じにするのに、代入が連鎖している事に注意してください — これで全く問題ありません。</p> + +<p>初期化スクリプトの最後の部分はこんなのです:</p> + +<pre class="brush: js notranslate">function random(min, max) { + const num = Math.floor(Math.random() * (max - min + 1)) + min; + return num; +}</pre> + +<p>この関数は二つの数を引数に取り、二つ数の範囲内の乱数を戻します。</p> + +<h2 id="Modeling_a_ball_in_our_program" name="Modeling_a_ball_in_our_program">我々のプログラム用のボールを一つモデル化する</h2> + +<p>我々のプログラムでは画面中を跳ねまわるたくさんのボールがあります。これらのボールはどれも同じルールで動くので、1つのオブジェクトで表わすのが理に叶っています。まずはコードの最後に以下のコンストラクターを追加するところから始めましょう。</p> + +<pre class="brush: js notranslate">function Ball(x, y, velX, velY, color, size) { + this.x = x; + this.y = y; + this.velX = velX; + this.velY = velY; + this.color = color; + this.size = size; +}</pre> + +<p>ここではいくつかの引数を用意し、我々のプログラムの中で個々のボールが動作するのに必要なプロパティを定義しています:</p> + +<ul> + <li><code>x</code>、<code>y</code>座標 — ボールが画面のどこからスタートするか表わす水平と垂直の座標。これは 0(画面左上隅)からブラウザービューポートの幅と高さの(画面右下隅)間の値を取ります。</li> + <li>水平と垂直方向の速度(<code>velX</code> と <code>velY</code>) — 個々のボールには水平と垂直方向の速度が与えられます。実際にはアニメーションが開始されると、これらの値が <code>x</code>/<code>y</code>座標値に定期的に加算され、各フレームでこの値だけ移動していきます。</li> + <li><code>color</code> — 個々のボールには色がつけられます。</li> + <li><code>size</code> — 個々のボールには大きさがあります — ピクセルを単位とする半径で表わします。</li> +</ul> + +<p>これはプロパティを取り扱いましたが、メソッドはどうしましょう? プログラムの中ではボールに実際に何かさせたいわけです。</p> + +<h3 id="Drawing_the_ball" name="Drawing_the_ball">ボールを描画する</h3> + +<p>まず以下の <code>draw()</code> メソッドを <code>Ball()</code> のプロトタイプ(<code>prototype</code>)に追加しましょう:</p> + +<pre class="brush: js notranslate">Ball.prototype.draw = function() { + ctx.beginPath(); + ctx.fillStyle = this.color; + ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); + ctx.fill(); +}</pre> + +<p>この関数を使って、以前定義した 2D キャンバスコンテキスト(<code>ctx</code>)のメンバーを順に呼び出す方法で、ボール自身が画面に自分を描画する方法を教え込みます。コンテキストは紙のようなもので、ペンを使って何か描くように指示したいわけです:</p> + +<ul> + <li>まずは、<code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/beginPath">beginPath()</a></code> を使って紙に形を描きたいと宣言します。</li> + <li>次に <code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/fillStyle">fillStyle</a></code> を使って形を何色にしたいか宣言します — ここではボールの <code>color</code> プロパティを指定します。</li> + <li>次に <code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/arc">arc()</a></code> メソッドを使って紙に円弧形をなぞります。これの引数は: + <ul> + <li>円弧の中心座標、<code>x</code> と <code>y</code> — ボールの <code>x</code>、<code>y</code> プロパティを指定します。</li> + <li>円弧の半径 — ここではボールの <code>size</code> プロパティです。</li> + <li>最後の二つの引数は円弧の開始点から終了点までの角度を円の中心角で指定します。ここでは 0度から <code>2 * PI</code>、これはラジアンで表わした 360度に相当します(ややこしいですがラジアンで指定しなければなりません)。これで一周した円を描けます。もし <code>1 * PI</code> までしか指定しなければ、半円(180度)になるでしょう。</li> + </ul> + </li> + <li>最後の最後に、<code><a href="/ja/docs/Web/API/CanvasRenderingContext2D/fill">fill()</a></code> メソッドを使って、これはおおよそ、「<code>beginPath()</code> から描き始めた線描を終了し、描いた領域を前に <code>fillStyle</code> で指定していた色で塗り潰せ」という指示になります。</li> +</ul> + +<p>これでオブジェクトをテストしてみられるようになりました。</p> + +<ol> + <li>コードを保存し、HTML ファイルをブラウザーで読み込みます。</li> + <li>ブラウザーの JavaScript コンソールを開いて、ページをリフレッシュし、キャンバスのサイズがコンソール分小さくなったビューポート領域に合うようにします。</li> + <li>次をタイプして、新しいボールのインスタンスを作成します: + <pre class="brush: js notranslate">let testBall = new Ball(50, 100, 4, 4, 'blue', 10);</pre> + </li> + <li>そのメンバを呼び出して見てください: + <pre class="brush: js notranslate">testBall.x +testBall.size +testBall.color +testBall.draw()</pre> + </li> + <li>最後の行を入力すると、キャンバスのどこかにボールが表示されたはずです。</li> +</ol> + +<h3 id="Updating_the_balls_data" name="Updating_the_balls_data">ボールのデータを更新する</h3> + +<p>ボールを座標に表示できるようになりましたが、ボールを実際に移動させるには、何らかの更新するための関数が必要です。JavaScript ファイルの最後に以下のコードを追加し、<code>update()</code> メソッドを <code>Ball()</code> の <code>prototype</code> に追加します:</p> + +<pre class="brush: js notranslate">Ball.prototype.update = function() { + if ((this.x + this.size) >= width) { + this.velX = -(this.velX); + } + + if ((this.x - this.size) <= 0) { + this.velX = -(this.velX); + } + + if ((this.y + this.size) >= height) { + this.velY = -(this.velY); + } + + if ((this.y - this.size) <= 0) { + this.velY = -(this.velY); + } + + this.x += this.velX; + this.y += this.velY; +}</pre> + +<p>関数の頭から 4 つの部分でボールがキャンバスの端に達したかどうかチェックします。もしそうであれば、関連する速度の向きを反転してボールが反対の向きに移動するようにします。つまり例えば、ボールが上方向に移動していたならば(<code>velY</code> が正)、垂直方向の速度をボールが下方向に移動するように変更します(<code>velY</code> を負に)。(<strong>訳注</strong>: 左上が原点、右下が座標の正方向ならば、ボールが上に移動する時の velY は負のはずだけど…)</p> + +<p>4 つの場合で、次のことを確認しています:</p> + +<ul> + <li><code>x</code>座標がキャンバスの幅より大きいか (ボールは右端から飛び出そうとしている)</li> + <li><code>x</code>座標が 0 より小さいか (ボールは左端から飛び出そうとしている)</li> + <li><code>y</code>座標がキャンバスの高さより大きいか (ボールは下端から飛び出そうとしている)</li> + <li><code>y</code>座標が 0 より小さいか (ボールは上端から飛び出そうとしている)</li> +</ul> + +<p>それぞれの場合で計算にボールの <code>size</code> を含めていますが、これは <code>x</code>/<code>y</code>座標はボールの中心ですが、ボールの端のところで周囲から跳ね返って欲しいからです — 跳ね返る前に画面外にめり込んで欲しくないからです。</p> + +<p>最後の二行では <code>velX</code> を <code>x</code> 座標に、<code>velY</code> を <code>y</code> 座標に加算しています — 結果ボールはこのメソッドが呼ばれる毎に移動します。</p> + +<p>とりあえずはここまでで、ちょいとアニメーションさせてみよう!</p> + +<h2 id="Animating_the_ball" name="Animating_the_ball">ボールのアニメーション</h2> + +<p>さあ、楽しい事をやりましょう。では、キャンバスにボールを追加し、アニメーションさせるところから始めましょう。</p> + +<ol> + <li>最初に、ボールを全部保存しておく場所がどこかに必要です。以下がこれをやってくれます — あなたのコードの最後に追加してください: + <pre class="brush: js notranslate">let balls = []; + +while (balls.length < 25) { + let size = random(10,20); + let ball = new Ball( + // ball position always drawn at least one ball width + // away from the edge of the canvas, to avoid drawing errors + random(0 + size,width - size), + random(0 + size,height - size), + random(-7,7), + random(-7,7), + 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')', + size + ); + + balls.push(ball); +}</pre> + + <p><code>while</code> ループは、我々の <code>random()</code>関数で作成したランダムな値を使った新しい <code>Ball()</code> のインスタンスを作成し、ボールの配列の後ろに <code>push()</code> して追加していきますが、これは配列中のボールの数が 25 に満たない間まで繰り返されます。<code>balls.length < 25</code> の数字をいろいろ変えれば表示されるボールの数を増やしたり減らしたりできます。あなたのコンピューターとブラウザーがどれだけ速いかによりますが、ボールを数千にするとアニメーションはかなり遅くなります! 注意してね。</p> + </li> + <li>以下をあなたのコードの末尾に追加してください: + <pre class="brush: js notranslate">function loop() { + ctx.fillStyle = 'rgba(0, 0, 0, 0.25)'; + ctx.fillRect(0, 0, width, height); + + for (let i = 0; i < balls.length; i++) { + balls[i].draw(); + balls[i].update(); + } + + requestAnimationFrame(loop); +}</pre> + + <p>ものをアニメーションさせるすべてのプログラムには、大概アニメーションループがあり、プログラム内の情報を更新して、アニメーションの各フレームでその結果を表示します。これは大半のゲームや類似するプログラムの基本になります。コード中の <code>loop()</code> 関数は以下の事を行ないます:</p> + + <ul> + <li>キャンバスの塗り潰し色を半透明の黒にし、その色でキャンバスの幅と高さいっぱいの長方形を <code>fillRect()</code> で描きます(これの 4 つの引数は始点の座標と、描画する長方形の幅と高さになります)。これで次のフレームを描く前に、前のフレームで描いた内容を見えなくします。これをしないと、ボールじゃなくて長い蛇がキャンバスの中を這い回る様を見る事になります! 塗り潰す色は半透明の <code>rgba(0,0,0,0.25)</code> なので、以前の何フレーム分かがかすかに残り、ボールが移動した後の軌跡を表現します。もし 0.25 を 1 に変更すると、軌跡は全く見えなくなります。この値を変えて、どんな効果になるか見てみてください。</li> + <li>ループで <code>balls</code>配列のボール全部をなめてそれぞれのボールの <code>draw()</code> と <code>update()</code> 関数を実行し、それぞれを画面に描画してから、次のフレームに備えて必要な位置と速度の更新を行います。</li> + <li>この関数を <code>requestAnimationFrame()</code> メソッドを使って再実行します — このメソッドが繰り返し実行され同じ関数名を与えられると、その関数がスムースなアニメーションを行なうために毎秒設定された回数実行されます。これはたいてい再帰的に行われます — つまり関数は毎回その関数自身を呼び出すので、何度も何度も繰り返し実行されます。</li> + </ul> + </li> + <li>最後に、あなたのコードの最後に次の行を追加します — アニメーションを開始するために、一旦は関数を呼ぶ必要があるのです。 + <pre class="brush: js notranslate">loop();</pre> + </li> +</ol> + +<p>基本としてはこんなところ — セーブしてリフレッシュして、ボールがはずむのをテストしてみてください!</p> + +<h2 id="Adding_collision_detection" name="Adding_collision_detection">衝突判定を追加する</h2> + +<p>さあ、もうちょっと面白くするため、プログラムに衝突判定を追加して、ボールに他のボールとぶつかったらどうするのか教えましょう。</p> + +<ol> + <li>最初に、以下のメソッド定義を <code>update()</code> メソッドを定義した箇所(つまり <code>Ball.prototype.update</code> ブロック)の下に追加します + + <pre class="brush: js notranslate">Ball.prototype.collisionDetect = function() { + for (let j = 0; j < balls.length; j++) { + if (!(this === balls[j])) { + const dx = this.x - balls[j].x; + const dy = this.y - balls[j].y; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < this.size + balls[j].size) { + balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')'; + } + } + } +}</pre> + </li> + <li> + <p>このメソッドはちょっとばかり複雑なので、今はどんな動作をしているのか正確に理解できなくても構いません。説明していきます:</p> + + <ul> + <li>それぞれのボールで、他のボールそれぞれとこのボールが衝突していないか調べなければなりません。そのために、<code>balls[]</code>配列すべてのボールを回すために別の <code>for</code> ループを始めます。</li> + <li>内側のループに入ってすぐ、<code>if</code>文でループで回しているボールがチェックしているボールと同じか調べています。ボールがそれ自体とぶつかっているかチェックしたくないですから! これのために、現在のボール(collisionDetect メソッドが実行されているボールです)がループ中のボール(現在の collisionDetect メソッド内のループのくりかえし中で参照されているボール)と一致しているかチェックします。<code>!</code>を使って等価性チェックを逆にしているので、<code>if</code> 文の中のコードはボールが<strong>同じでない</strong>ときだけ実行されます。</li> + <li>そして二つの円が衝突していないか調べるための一般的なアルゴリズムを使っています。基本的には円ないの領域が重なっているかチェックしています。これについて詳しくは <a href="/ja/docs/Games/Techniques/2D_collision_detection">2次元の衝突判定</a>で解説されています。</li> + <li>もし衝突が検出されたら、内側の <code>if</code>文の中のコードが実行されます。この場合では、両方のボールの <code>color</code> プロパティをランダムな新しい色に設定しているだけです。もっと複雑なこと、現実っぽくボールを互いに跳ね返らせたりもできたでしょうが、これを実装したとするともっとずっとに複雑なったでしょう。そのような物理シミュレーションには、<a href="http://wellcaffeinated.net/PhysicsJS/">PhysicsJS</a>, <a href="http://brm.io/matter-js/">matter.js</a>, <a href="http://phaser.io/">Phaser</a> などのゲームや物理用のライブラリを使う開発者が多いです。</li> + </ul> + </li> + <li>あなたはアニメーションの各フレーム毎にこのメソッドを呼ばなければなりません。以下を <code>balls[i].update();</code> の行の後に追加してください: + <pre class="brush: js notranslate">balls[i].collisionDetect();</pre> + </li> + <li>保存とデモのリフレッシュをして、ボールがぶつかった時に色が変わるのを見てください!</li> +</ol> + +<div class="note"> +<p><strong>注記</strong>: この例題を動かすのに困った時は、あなたの JavaScript コードを私たちの<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main-finished.js">完成版</a>と比べてみてください(<a href="http://mdn.github.io/learning-area/javascript/oojs/bouncing-balls/index-finished.html">ライブ実行版</a>も見られます)。</p> +</div> + +<h2 id="Summary" name="Summary">まとめ</h2> + +<p>自分版の実世界で跳ね回るランダムボール例作り、この全単元で出てきた様々なオブジェクトやオブジェクト指向テクニックを使ったものをあなたに楽しんでいただけていれば、と思います。オブジェクトの実践的な使い方の練習や、実世界のコンテキストについて得られるものがあったはずです。</p> + +<p>オブジェクトに関する記事は以上です — 残るのは、あなが自分のスキルをオブジェクトの評価問題で試してみる事だけです。</p> + +<h2 id="See_also" name="See_also">参考文献</h2> + +<ul> + <li><a href="/ja/docs/Web/API/Canvas_API/Tutorial">Canvas tutorial</a> — 2D キャンバスの初心者向けガイド。</li> + <li><a href="/ja/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></li> + <li><a href="/ja/docs/Games/Techniques/2D_collision_detection">2D collision detection</a></li> + <li><a href="/ja/docs/Games/Techniques/3D_collision_detection">3D collision detection</a></li> + <li><a href="/ja/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript">2D breakout game using pure JavaScript</a> — 2D ゲームの作り方に関する、素晴しい初心者向けチュートリアル。</li> + <li><a href="/ja/docs/Games/Tutorials/2D_breakout_game_Phaser">2D breakout game using Phaser</a> — JavaScript ゲームライブラリを使って 2D ゲームを作るための基本を解説しています。</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/object_prototypes/index.html b/files/ja/learn/javascript/objects/object_prototypes/index.html new file mode 100644 index 0000000000..4e9419e49d --- /dev/null +++ b/files/ja/learn/javascript/objects/object_prototypes/index.html @@ -0,0 +1,314 @@ +--- +title: Object のプロトタイプ +slug: Learn/JavaScript/Objects/Object_prototypes +tags: + - Beginner + - CodingScripting + - JavaScript + - Learn + - OOJS + - OOP + - Object + - Prototype + - create() + - 'l10n:priority' + - コンストラクタ + - 記事 +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">プロトタイプは、JavaScript オブジェクトが互いに機能を継承するメカニズムです。この記事では、プロトタイプチェーンの仕組みを説明し、<code>prototype</code> プロパティを使って既存のコンストラクタにメソッドを追加する方法を見ていきます。</p> + +<div class="blockIndicator note"> +<p class="summary"><strong>Note</strong>: この記事では、伝統的な JavaScript のコンストラクタとクラスを取り上げます。次の記事では、同じことを実現するためのより簡単な構文を提供する現代的な方法について話します - <a href="/ja/docs/Learn/JavaScript/Objects/Inheritance#ECMAScript_2015_Classes">ECMAScript 2015 のクラス</a>を参照してください。</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>JavaScript 関数の理解、JavaScript の基礎知識 (<a href="/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a>と<a href="/ja/docs/Learn/JavaScript/Building_blocks">JavaScript の構成要素</a>を参照)、OOJS の基礎 (<a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a>を参照)</td> + </tr> + <tr> + <th scope="row">目的:</th> + <td>JavaScript のオブジェクトのプロトタイプ、プロトタイプチェーンの動作方法、prototype プロパティに新しいメソッドを追加する方法を理解する。</td> + </tr> + </tbody> +</table> + +<h2 id="プロトタイプベースの言語とは">プロトタイプベースの言語とは?</h2> + +<p>JavaScript はしばしば<strong>プロトタイプベースの言語</strong>として記述されます - 継承を提供するために、オブジェクトはメソッドやプロパティを継承するテンプレートオブジェクトとして機能する <strong><code>prototype</code> オブジェクト</strong>を持つことができます。</p> + +<p>オブジェクトのプロトタイプオブジェクトは、メソッドやプロパティを継承するプロトタイプオブジェクトを持つことができます。これはしばしば<strong>プロトタイプチェーン</strong>と呼ばれ、異なるオブジェクトが他のオブジェクトに定義されたプロパティやメソッドを持つ理由を説明しています。</p> + +<p>JavaScript では、オブジェクトのインスタンスとプロトタイプ (コンストラクタの <code>prototype</code> プロパティから派生した <code>__proto__</code> プロパティ) の間にリンクが張られており、プロパティとメソッドはプロトタイプの連鎖を辿って見つけられます。</p> + +<div class="note"> +<p><strong>Note:</strong> <strong>オブジェクトの <code>prototype</code></strong> (<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf">Object.getPrototypeOf(<var>obj</var>)</a></code> または非推奨の <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code> プロパティで取得可能) と<strong>コンストラクタ関数の<code>prototype</code> プロパティ</strong>の違いを理解することが重要です。</p> + +<p>前者は各インスタンス上のプロパティ、後者はコンストラクタ上のプロパティです。つまり、<code>Object.getPrototypeOf(new <var>Foobar</var>())</code> は<code><var>Foobar</var>.prototype</code>と同じオブジェクトを参照しています。</p> +</div> + +<p>これを少し明確にするための例を見てみましょう。</p> + +<h2 id="プロトタイプオブジェクトの理解">プロトタイプオブジェクトの理解</h2> + +<p>ここでは、Person() コンストラクタを書き終えた例に戻ります - ブラウザで例を読み込んでください。前回の記事で紹介した <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> の例を使うことができます (<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">ソースコード</a>も参照してください)。</p> + +<p>この例では、次のようにコンストラクタ関数を定義しています。</p> + +<pre class="brush: js notranslate">function Person(first, last, age, gender, interests) { + + // property and method definitions + this.name = { + 'first': first, + 'last' : last + }; + this.age = age; + this.gender = gender; + //...see link in summary above for full definition +}</pre> + +<p>次に、このようなオブジェクトインスタンスを作成します。</p> + +<pre class="brush: js notranslate">let person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + +<p>JavaScript コンソールに "<code>person1.</code>" と入力すると、ブラウザがこのオブジェクトで利用可能なメンバ名でこれを自動補完しようとするはずです:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13853/object-available-members.png" style="display: block; margin: 0 auto;"></p> + +<p>このリストでは、<code>person1</code> のコンストラクタである <code>Person()</code> で定義されているメンバ - <code>name</code>、<code>age</code>、<code>gender</code>、<code>interests</code>、<code>bio</code>、<code>greeting</code> - が表示されています。しかし、他にも <code>toString</code> や <code>valueOf</code> などのメンバがあり、これらのメンバは <code>person1</code> の prototype オブジェクトの prototype オブジェクト (<code>Object.prototype</code>) で定義されています。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13891/MDN-Graphics-person-person-object-2.png" style="display: block; height: 150px; margin: 0px auto; width: 700px;"></p> + +<p>実際に <code>Object.prototype</code> で定義されている <code>person1</code> のメソッドを呼び出すとどうなりますか?例えば</p> + +<pre class="brush: js notranslate">person1.valueOf()</pre> + +<p><code>valueOf()</code> は、呼び出されたオブジェクトの値を返します。この場合、何が起こるかというと</p> + +<ul> + <li>ブラウザは最初に、<code>person1</code> オブジェクトのコンストラクタ <code>Person()</code> で定義されている <code>valueOf()</code> メソッドが利用可能かどうかをチェックしますが、利用できません</li> + <li>そこで、ブラウザは <code>person1</code> のプロトタイプオブジェクトに <code>valueOf()</code> メソッドが利用可能かどうかをチェックします。メソッドがない場合、ブラウザは <code>person1</code> のプロトタイプオブジェクトのプロトタイプオブジェクトをチェックします。メソッドが呼び出されて、すべてがうまくいきました</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: プロトタイプチェーンの中では、メソッドやプロパティはあるオブジェクトから別のオブジェクトにコピー<strong>されない</strong>ことを再確認しておきましょう。これらのメソッドやプロパティは、上で説明したように<em>チェーンを上っていく</em>ことで<em>アクセス</em>されます。</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: プロトタイプチェーンは、プロパティを取得している間のみ巡回されます。プロパティがオブジェクトに直接設定されたり<code><a href="/ja/docs/Web/JavaScript/Reference/Operators/delete">削除されたり</a></code>した場合は、プロトタイプチェーンは走査されません。</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: ECMAScript 2015 以前は、オブジェクトの <code>prototype</code> に直接アクセスする方法は公式にはありませんでした - チェーン内のアイテム間の「リンク」は、JavaScript 言語の仕様で <code>[[prototype]]</code> と呼ばれる内部プロパティで定義されています ({{glossary("ECMAScript")}}}を参照してください)。</p> + +<p>しかし、ほとんどの最新のブラウザでは、オブジェクトのコンストラクタのプロトタイプオブジェクトを含む <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code> (アンダースコア2個分) というプロパティを提供しています。例えば、<code>person1.__proto__</code> と <code>person1.__proto__.__proto__</code> を試してみてください。</p> + +<p>ECMAScript 2015 からは、<code>Object.getPrototypeOf(obj)</code> を介して間接的にオブジェクトのプロトタイプオブジェクトにアクセスすることができます。</p> +</div> + +<h2 id="prototypeプロパティ:継承されたメンバーが定義されている場所">prototypeプロパティ:継承されたメンバーが定義されている場所</h2> + +<p>では、継承されたプロパティとメソッドはどこに定義されているのでしょうか? <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code>リファレンスページを見ると、左側に多数のプロパティとメソッドが表示されます。上のスクリーンショットで<code>person1</code>オブジェクトで使用できた継承されたメンバーの数を超えています。いくつかは継承されており、一部は継承されていません。これはなぜでしょうか?<br> + <br> + 上で述べたように、継承されたものは <code>prototype</code> プロパティ (サブネームスペースと呼ぶこともできます) で定義されたものであり、それは <code>Object.prototype.</code> で始まるものであって、<code>Object.</code> だけで始まるものではありません。<code>prototype</code> プロパティの値はオブジェクトであり、基本的には、プロトタイプチェーンのさらに下のオブジェクトに継承させたいプロパティやメソッドを格納するためのバケットです。<br> + <br> + そのため、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/toString">Object.prototype.toString()</a></code>、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf()</a></code> などは、<code>Person()</code> コンストラクタから作成された新しいオブジェクトインスタンスを含め、<code>Object.prototype</code> を継承するあらゆるオブジェクトタイプで利用できます。</p> + +<p><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is()</a></code>、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code> など、<code>prototype</code> バケット内で定義されていないメンバは、<code>Object.prototype</code> を継承するオブジェクトインスタンスやオブジェクトタイプには継承されません。これらは、<code>Object()</code> コンストラクタ自身でのみ利用可能なメソッド/プロパティです。</p> + +<div class="note"> +<p><strong>Note</strong>: コンストラクタ上で定義されたメソッドが、それ自体が関数であるというのは不思議な感じがします。</p> + +<p>まあ、関数はオブジェクトの型でもあります。信じられないかもしれませんが、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function">Function()</a></code> のコンストラクタリファレンスを参照してください。</p> +</div> + +<ol> + <li>既存のプロトタイプのプロパティを自分でチェックすることができます。先ほどの例に戻って、JavaScript コンソールに次のように入力してみてください + <pre class="brush: js notranslate">Person.prototype</pre> + </li> + <li>カスタムコンストラクタのプロトタイプに何も定義していないので、出力はあまり表示されません。デフォルトでは、コンストラクタの <code>prototype</code> は常に空から始まります。では、次のようにしてみてください + <pre class="brush: js notranslate">Object.prototype</pre> + </li> +</ol> + +<p>先ほど示したように、<code>Object</code> の <code>prototype</code> プロパティに定義された多数のメソッドが、<code>Object</code> を継承するオブジェクトで利用できるようになっています。</p> + +<p>プロトタイプチェーン継承の他の例は、JavaScript の至る所で見ることができます。例えば、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></code>、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a></code>、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code> などのグローバルオブジェクトのプロトタイプに定義されているメソッドやプロパティを探してみてください。これらはすべて、プロトタイプに定義されたいくつかのメンバを持っており、例えばこのように文字列を作るとき</p> + +<pre class="brush: js notranslate">let myString = 'This is my string.';</pre> + +<p><code>myString</code>が最初から、<code><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/split">split()</a></code>、<code><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf">indexOf()</a></code>、<code><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a></code>などの便利なメソッドを多数持っている理由です。</p> + +<div class="note"> +<p><strong>Note</strong>: このセクションを理解して、もっと知りたいと思ったら、<a href="/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Using_prototypes_in_JavaScript">JavaScript でのプロトタイプの使用</a> についてのより詳細なガイドを読む価値があります。このセクションは、これらの概念に初めて出会ったときに少しでも理解しやすくするために、意図的に簡略化しています。</p> +</div> + +<div class="warning"> +<p><strong>重要</strong>: <code>prototype</code> プロパティは JavaScript の中でも最も紛らわしい名前がついている部分の一つです (<code>this</code> は <code>__proto__</code> でアクセスできる内部オブジェクトです、覚えていますか?)。代わりに <code>prototype</code> は、継承したいメンバを定義したオブジェクトを含むプロパティです。</p> +</div> + +<h2 id="create_の再訪">create() の再訪</h2> + +<p>先ほど、<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/create">Object.create()</a></code> メソッドを使用して新しいオブジェクトのインスタンスを作成する方法を紹介しました。</p> + +<ol> + <li>例えば、先ほどの例の JavaScript コンソールでこれを試してみてください + <pre class="brush: js notranslate">let person2 = Object.create(person1);</pre> + </li> + <li><code>create()</code> が実際に行うことは、指定したプロトタイプオブジェクトから新しいオブジェクトを作成することです。ここでは、<code>person1</code> をプロトタイプオブジェクトとして使用して <code>person2</code> を作成しています。これはコンソールで以下のように入力することで確認できます + <pre class="brush: js notranslate">person2.__proto__</pre> + </li> +</ol> + +<p>これで <code>person1</code> オブジェクトが返されます。</p> + +<h2 id="コンストラクタのプロパティ">コンストラクタのプロパティ</h2> + +<p>すべてのコンストラクタ関数は <code>prototype</code> プロパティを持ち、その値は <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> プロパティを含むオブジェクトとなります。この <code>constructor</code> プロパティは、元のコンストラクタ関数を指します。</p> + +<p>次のセクションでお分かりのように、<code>Person.prototype</code> プロパティ (あるいは上のセクションで述べたように、一般的にはコンストラクタ関数の <code>prototype</code> プロパティに定義されているオブジェクト) は、<code>Person()</code> コンストラクタを使用して作成されたすべてのインスタンスオブジェクトで利用可能になります。したがって、コンストラクタプロパティは <code>person1</code> と <code>person2</code> の両方のオブジェクトでも利用可能です。</p> + +<ol> + <li>例えば、コンソールで次のコマンドを試してみてください + <pre class="brush: js notranslate">person1.constructor +person2.constructor</pre> + + <p>これらのインスタンスの元の定義を含む <code>Person()</code> コンストラクタを返します。</p> + + <p>巧妙なトリックとしては、<code>constructor</code> プロパティの最後に括弧を付けて (必要なパラメータを含む)、そのコンストラクタから別のオブジェクトのインスタンスを作成することができます。コンストラクタは結局のところ関数なので、括弧を使用して呼び出すことができます。関数をコンストラクタとして使用したい場合は、<code>new</code> キーワードを含めて指定する必要があります。</p> + </li> + <li>これをコンソールで試してみてください + <pre class="brush: js notranslate">let person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);</pre> + </li> + <li>では、新しいオブジェクトの機能にアクセスしてみましょう + <pre class="brush: js notranslate">person3.name.first +person3.age +person3.bio()</pre> + </li> +</ol> + +<p>これはよく機能します。頻繁に使用する必要はありませんが、新しいインスタンスを作成したいときに、何らかの理由で元のコンストラクタへの参照が簡単に利用できない場合に非常に便利です。</p> + +<p><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> プロパティには他の用途もあります。たとえば、オブジェクトのインスタンスがあり、そのインスタンスのコンストラクタの名前を返したい場合は次のようにします。</p> + +<pre class="brush: js notranslate">instanceName.constructor.name</pre> + +<p>たとえば、これを試してみてください:</p> + +<pre class="brush: js notranslate">person1.constructor.name +</pre> + +<div class="note"> +<p><strong>Note</strong>: <code>constructor.name</code> の値は (プロトタイプの継承、バインディング、プリプロセッサ、トランスパイラなどによる) 変わる可能性があります。そのため、より複雑な例では、代わりに <code><a href="/ja/docs/Web/JavaScript/Reference/Operators/instanceof">instanceof</a></code> 演算子を使用することになります。</p> +</div> + +<ol> +</ol> + +<h2 id="プロトタイプの変更">プロトタイプの変更</h2> + +<p>コンストラクタ関数の <code>prototype</code> プロパティを変更する例を見てみましょう - メソッドは、コンストラクタから作成されたすべてのオブジェクトインスタンスで利用可能になります。この時点で、最後に <code>Person()</code> コンストラクタのプロトタイプに何かを追加します。</p> + +<ol> + <li><a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> の例に戻り、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">ソースコード</a>のローカルコピーを作成します。既存の JavaScript の下に、コンストラクタの <code>prototype</code> プロパティに新しいメソッドを追加する次のコードを追加します + + <pre class="brush: js notranslate">Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + </li> + <li>コードを保存してブラウザでページを読み込み、テキスト入力に以下のように入力してみてください + <pre class="brush: js notranslate">person1.farewell();</pre> + </li> +</ol> + +<p>コンストラクタ内で定義されている人の名前を特徴とする警告メッセージが表示されるはずです。これは本当に便利ですが、さらに便利なのは継承チェーン全体が動的に更新され、コンストラクタから派生したすべてのオブジェクトインスタンスでこの新しいメソッドが自動的に利用できるようになったことです。</p> + +<p>ちょっと考えてみましょう。このコードでは、コンストラクタを定義し、そのコンストラクタからインスタンスオブジェクトを作成し、コンストラクタのプロトタイプに新しいメソッドを追加しています。</p> + +<pre class="brush: js notranslate">function Person(first, last, age, gender, interests) { + + // プロパティおよびメソッドを定義する + +} + +let person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']); + +Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + +<p>しかし、<code>farewell()</code> メソッドは <code>person1</code> オブジェクトのインスタンスで利用可能です。そのメンバーは、新たに定義された <code>farewell()</code> メソッドを含むように自動的に更新されます。</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 逆に、コンストラクタのプロトタイプに定義されたプロパティを <code><a href="/ja/docs/Web/JavaScript/Reference/Operators/delete">delete</a></code> 演算子を使用して削除すると、他のすべてのクラスインスタンスからもそれぞれのプロパティが削除されます。</p> + +<p>上記の例では、<code>delete person1.__proto__.farewell</code> または <code>delete Person.prototype.farewell</code> を実行すると、すべての <code>Person</code> インスタンスから <code>farewell()</code> メソッドが削除されます。</p> + +<p>この問題を軽減するために、代わりに <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty()</a></code> を使用することができます。</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: この例がうまく動作しない場合は、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-prototype.html">oojs-class-prototype.html</a> の例を見てください (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-prototype.html">ライブ</a>でも参照してください) 。</p> +</div> + +<p>このように定義されたプロパティは柔軟性に欠けるため、<code>prototype</code> プロパティで定義されることはほとんどありません。例えば、次のようなプロパティを追加することができます。</p> + +<pre class="brush: js notranslate">Person.prototype.fullName = 'Bob Smith';</pre> + +<p>これはその person がその名前で呼ばれていないかもしれないので、あまり柔軟性がありません。<code>name.first</code> と <code>name.last</code> から <code>fullName</code> を作成する方がずっと良いでしょう。</p> + +<pre class="brush: js notranslate">Person.prototype.fullName = this.name.first + ' ' + this.name.last;</pre> + +<p>しかし、これではうまくいきません。この場合、<code>this</code> は関数スコープではなくグローバルスコープを参照するからです。このプロパティを呼び出すと <code>undefined</code> を返します。これは、先ほどプロトタイプで定義したメソッドでは問題なく動作したのはそれがオブジェクトのインスタンススコープに正常に転送される関数スコープ内にあるためです。そのため、プロトタイプ上で不変の(つまりだれも変更する必要のない)プロパティを定義することもできますが、一般的にはコンストラクタ内でプロパティを定義する方がうまくいきます。</p> + +<p>実際、多くのオブジェクト定義でよく見られるパターンは、コンストラクタ内でプロパティを定義し、プロトタイプ上でメソッドを定義することです。これにより、コンストラクタにはプロパティの定義のみが含まれ、メソッドは別のブロックに分割されるため、コードが読みやすくなります。例えば、以下のようになります。</p> + +<pre class="brush: js notranslate">// Constructor with property definitions + +function Test(a, b, c, d) { + // プロパティ定義 +} + +// 最初のメソッド定義 + +Test.prototype.x = function() { ... }; + +// 第二のメソッド定義 + +Test.prototype.y = function() { ... }; + +// など</pre> + +<p>このパターンは、Piotr Zalewa 氏の<a href="https://github.com/zalun/school-plan-app/blob/master/stage9/js/index.js">学校計画のアプリ</a>の例で実際に見られます。</p> + +<h2 id="あなたのスキルをテストしてみましょう!">あなたのスキルをテストしてみましょう!</h2> + +<p>この記事はここまでですが、最も重要な情報を覚えていますか?先に進む前に、この情報を保持しているかどうかを確認するために、さらにいくつかのテストを見つけることができます。<a href="/ja/docs/Learn/JavaScript/Objects/Test_your_skills:_Object-oriented_JavaScript">あなたのスキルをテストする: オブジェクト指向 JavaScript</a> を参照してください。</p> + +<p>この一連のテストは次の記事で紹介する知識に依存していることに注意してください。なので、試してみる前に、まずそれを読んでみるといいかもしれません。</p> + +<h2 id="まとめ">まとめ</h2> + +<p>この記事では、プロトタイプオブジェクトチェーンによってオブジェクトが互いに機能を継承する方法、プロトタイププロパティとそれを使ってコンストラクタにメソッドを追加する方法など、JavaScript オブジェクトのプロトタイプを取り上げてきました。</p> + +<p>次の記事では、2つのカスタムオブジェクト間で機能の継承を実装する方法を見ていきます。</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS">初心者のためのオブジェクト指向 JavaScript</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_prototypes">Object のプロトタイプ</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Inheritance">JavaScript での継承</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/JSON">JSON データの操作</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Object_building_practice">オブジェクト作成の練習</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">バウンスボールに機能を追加する</a></li> +</ul> diff --git a/files/ja/learn/javascript/objects/test_your_skills_colon__object_basics/index.html b/files/ja/learn/javascript/objects/test_your_skills_colon__object_basics/index.html new file mode 100644 index 0000000000..d284729df3 --- /dev/null +++ b/files/ja/learn/javascript/objects/test_your_skills_colon__object_basics/index.html @@ -0,0 +1,101 @@ +--- +title: 'スキルテスト: オブジェクトの基本' +slug: 'Learn/JavaScript/Objects/Test_your_skills:_Object_basics' +translation_of: 'Learn/JavaScript/Objects/Test_your_skills:_Object_basics' +--- +<div>{{learnsidebar}}</div> + +<p>このスキルテストの目的は、<a href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics">JavaScript オブジェクトの基本</a>の理解度をテストすることです。</p> + +<div class="blockIndicator note"> +<p><strong>注意</strong>: 以下のインタラクティブなエディターでソリューションを試すこともできますが、コードをダウンロードし、<a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>や<a href="https://glitch.com/">Glitch</a>のようなオンラインツールを使用してタスクを実行すると役立つ場合があります。<br> + <br> + 行き詰まった場合は、助けを求めてください — このページの下部にある評価またはさらなる支援セクションを参照してください。</p> +</div> + +<div class="blockIndicator note"> +<p><strong>注意</strong>: 以下の例では、コードにエラーがある場合、ページの結果パネルに出力され、答えを見つけ出すのに役立ちます(ダウンロード可能なバージョンの場合は、ブラウザーのJavaScriptコンソールに)</p> +</div> + +<h2 id="オブジェクトの基本_1">オブジェクトの基本 1</h2> + +<p>このタスクでは、オブジェクトリテラルが与えられます。あなたのタスクは下記です。</p> + +<ul> + <li><code>catName</code>変数に、<strong>角括弧記法</strong>を用いて、<code>name</code>プロパティの値を保存する</li> + <li><strong>ドット記法</strong>を用いて、<code>greeting()</code>メソッドを使う</li> + <li><code>color</code>プロパティを<code>black</code>に変更する</li> +</ul> + +<p>以下のライブコードを更新して、完成した例を再現してみてください。</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/oojs/tasks/object-basics/object-basics1.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/oojs/tasks/object-basics/object-basics1-download.html">このタスクの開始点をダウンロード</a>して、お好きなエディターまたはオンライン・エディターで作業してください。</p> +</div> + +<h2 id="オブジェクトの基本_2">オブジェクトの基本 2</h2> + +<p>次のタスクでは、お気に入りのバンドの1つを表す、自分だけのオブジェクトリテラルを作成してみましょう。必要な要素は次のとおりです。</p> + +<ul> + <li><code>name</code>: バンドの名前を表す文字列</li> + <li><code>nationality</code>: バンドの出身国を表す文字列</li> + <li><code>genre</code>: バンドが演奏する音楽の種類</li> + <li><code>members</code>: バンドのメンバー数を表す数字</li> + <li><code>formed</code>: バンドが結成した年を表す数字</li> + <li><code>split</code>: バンドが解散した年を表す数字、まだ活動している場合は<code>false</code></li> + <li><code>albums</code>: そのバンドによってリリースされたアルバムを表す配列。それぞれの配列の要素は、下記の要素を含んだオブジェクトであること + <ul> + <li><code>name</code>: アルバムの名前を表す文字列</li> + <li><code>released</code>: リリースされた年を表す数字</li> + </ul> + </li> +</ul> + +<p><code>albums</code> 配列には、少なくとも2つのアルバムを含めること。</p> + +<p>これが終わったら、変数<code>bandInfo</code>に、名前、国籍、活動年数、スタイル、最初のアルバムのタイトルと発売日などの少しの詳細を書き込みます。</p> + +<p><span style="">以下のライブコードを更新して、完成した例を再現してみてください。</span></p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/oojs/tasks/object-basics/object-basics2.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/oojs/tasks/object-basics/object-basics1-download.html">このタスクの開始点をダウンロード</a>して、お好きなエディターまたはオンライン・エディターで作業してください。</p> +</div> + +<h2 id="オブジェクトの基本_3">オブジェクトの基本 3</h2> + +<p>最後に、「オブジェクトの基本」のまとめとして、タスク#1の<code>cat</code>オブジェクトリテラルに戻りましょう。 「<code>Hello, said Bertie the Cymric.</code>」と記録されるように、<code>greeting()</code>メソッドを書き直してください。 ブラウザのDevToolsのコンソールにアクセスしますが、名前や品種に関係なく、同じ構造のすべての<code>cat</code>オブジェクトで機能します。</p> + +<p>完了したら、<code>cat2</code>という独自のオブジェクトを作成します。このオブジェクトは、同じ構造、まったく同じ<code>greeting()</code>メソッドを持ちますが、名前、品種、色が異なります。</p> + +<p>両方の<code>greeting()</code>メソッドを呼び出して、適切なあいさつ(greeting)がコンソールに記録されることを確認します。</p> + +<p>コードはあまり<a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>ではありません(それぞれは1回だけ定義すること)—たとえば、同じメソッドを2回定義しています。 どうすればもっとDRYにすることができますか? よくわからない場合でも、心配しないでください。これは、シリーズの今後の記事で取り上げる予定です。</p> + +<p>以下のライブコードを更新して、完成した例を再現してみてください。</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/oojs/tasks/object-basics/object-basics3.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/oojs/tasks/object-basics/object-basics1-download.html">このタスクの開始点をダウンロード</a>して、お好きなエディターまたはオンライン・エディターで作業してください。</p> +</div> + +<h2 id="まとめとヘルプ">まとめとヘルプ</h2> + +<p>自分のコードの評価が欲しい、または行き詰まって助けを求めたい場合:</p> + +<ol> + <li>CodePen、jsFiddle、Glitchなどのオンライン共有可能なエディターで作業をします。コードを自分で作成することも、上記のセクションでリンクされているスターティングポイントファイルを使用することもできます。</li> + <li><a href="https://discourse.mozilla.org/c/mdn/learn/250">MDNDiscourseフォーラムの学習カテゴリ</a>で評価や支援を求める投稿を書いてください。投稿には次のものを含める必要があります。</li> +</ol> + +<ul> + <li>「オブジェクトの基本1 の スキルテスト を行ったので評価して欲しい」などの説明的なタイトル。</li> + <li>あなたがすでに試したことの詳細、そしてあなたが私たちに何をしてほしいか、例えば行き詰まって助けが必要な場合、または評価が必要な場合。</li> + <li>オンラインの共有可能なエディターで、評価したい、または支援が必要な例へのリンク(上記のステップ1で説明)。これは入門するのに良い習慣です—あなたが彼らのコードを見ることができないならば、コーディング問題で誰かを助けることは非常に難しいです。</li> + <li>実際のタスクまたは評価ページへのリンク。サポートが必要な質問を見つけることができます。</li> +</ul> |