DHC-オンライン講座
文系の人にもわかる プログラミング入門

付録 オブジェクト指向とJavaScript

TextbookではJavaScriptのプログラムそのものについて説明しましたが, 付録として, プログラミング言語としてのJavaScriptについてその位置づけや背景を説明しておきます。

メモ

この付録では, これまでとは違って概念的な話が多くなります。 JavaScriptのプログラムを作る際には, 当面, 知らなくてもすむことですが, 知識を整理するのには役立つはずです。 今まで登場してきた概念を別の角度から見ることによって, プログラミングに関する別の種類の「感覚」が得られると思います。

オブジェクト指向とJavaScript

この世の中は「もの(オブジェクト)」でできています。

ここでいう「もの」は, 物体としてその実体を見たり触ったりできる「物」には限りません。 概念とか, 考え方とか, 宗教とか, そういった抽象的なものまで含めます。

世の中は「もの」でできているのですから, 「もの」を中心にしてプログラムを作れば, 世の中の「もの」をコンピュータで扱うのに便利だろうと考えた人たちがいました。 これが「オブジェクト指向プログラミング」という考え方です。

こういった考え方は, 源をたどれば1970年代ぐらいからいくつか出てきていました。 1980年代にはこのような考え方の研究が盛んに行われてはいたが, まだ実用に供されることは多くはありませんでした。 しかし, その考え方に同調する人は確実に増えていき, 1990年代にはいり, この考え方に基づいたプログラミングの手法が, プログラム開発の主流を占めるようになりました。 そして, 新しく提案されるプログラミング言語には, オブジェクト指向の機能が必ず取り入れられるようになりました。 当然, 1990年代中盤に生まれたJavaScriptにも, オブジェクト指向の機能が取り入れられたというわけです。 オブジェクト指向の考え方を取り入れたプログラミング言語を「オブジェクト指向プログラミング言語」といいます。 JavaScriptもオブジェクト指向プログラミング言語のひとつといってよいでしょう。

プログラミングで「もの」を扱う場合, 「もの」がもつ「性質」と「それに対して行う操作」でその「もの」を特徴づけると便利だ(ということでみんなの合意ができてきました)。 この「性質」のことをオブジェクト指向の世界では「プロパティ(property)」あるいは「属性」という言葉で表現し, 機能のことを「メソッド」という言葉で表現します。

たとえば, オブジェクトとして「テレビ」を考えるとき, プロパティとしては, 画面の大きさ, 値段, 色, メーカー, 型番, 重さ, 表示方式(ブラウン管か液晶かプラズマか), 高さ, 奥行, 保証期間, 製造年月日, 使われている部品の数, などが考えられるでしょう。 また, メソッドとしては「スイッチを入れる」「スイッチを切る」「チャンネルを指定する」「画面をの明るさを変える」「入力を切り替える」などが考えられます。

ここで, 注意しておきたいのは, プログラムを作る場合には, そのプログラムで必要となるプロパティやメソッドだけを記述すればよいということです。 テレビの販売を管理するプログラムを書くときに, 「使われている部品の数」を覚えておく必要はないでしょうから, これに関する記述は必要ありません。 また, 販売管理をするのに, スイッチを入れたり切ったりといたメソッドは必要がないはずです(もうテストはすんでいるものがメーカーから送られてくるのですから)。

JavaScriptとブラウザの仲介役 ── ドキュメントオブジェクトモデル

JavaScriptが扱う「もの」は何でしょうか。 JavaScriptのプログラムはブラウザのウィンドウに表示される「もの」を扱い, ウィンドウの中には次のような「もの(オブジェクト)」が登場します。

そのほか, これまでこの本では触れなかったが次のような「もの」も存在します。

また, ブラウザ自体には直接関係しませんが, 次のような「もの」も扱ってきました。

このようなさまざまなもの(オブジェクト)を, JavaScriptでは「ドキュメントブジェクトモデル(Document Object Model, 略してDOM)」という概念を使って整理しています。 「オブジェクトモデル」ということからわかるように, この考え方は「オブジェクト指向プログラミング」の考え方に基づいています。 つまり, ブラウザに関係するすべての「もの」の性質(プロパティ)や機能(メソッド)を, DOMは表現しているわけです。

DOMのオブジェクトと階層構造

上にあげたようなものは, すべてDOMに登場するオブジェクトで, JavaScriptから何らかの形で参照したり, 変更したりできるようになっています。 たとえば, ウィンドウそのものを表現するオブジェクトはwindowという名前で参照できますし, ウィンドウ内に表示されるドキュメントはdocumentという名前で参照できるのです。

また, これらのオブジェクトは図A-1のような階層をなしています(ただし, windowの下にあるframesの要素はwindowオブジェクトになるといった具合に一直線の階層構造ではありません)。

図A-1 DOMのオブジェクトの階層構造(一部)

ブラウザに直接関係するオブジェクトで, 一番上に位置するのがwindowという名前のオブジェクトです。 これはブラウザのウィンドウを表します。 ブラウザのウィンドウ内のことを操作するのがJavaScriptなので, これが一番上にあるというのは自然な話でしょう。 windowの下には, document, frames, history, location, screenなどのオブジェクトが, そしてdocumentの下にはforms, applet, imagesなどのオブジェクトがあります。

この階層を上から, window→document→forms→textとたどってみましょう。 formsは, ドキュメント内に含まれるフォームを表すオブジェクト, textはフォーム内のテキスト領域を表現するものです。

これを頭においてLesson 10で出てきた次の表現を見てみましょう(図A-2)。

    document.yomiganaForm.kanji.value

この表現は, ドキュメントオブジェクト内に含まれる, 「yomiganaFormというフォーム内にある, kanjiという名前のテキスト領域の値」を示すものでした。 つまりこの表現は, DOMの階層構造をたどっていたのです。

図A-2 DOMの階層構造とdocument.yomiganaForm.kanji.value

DOMオブジェクトのプロパティ

なぜ, このように階層をたどっていけばよいのでしょうか。 それはDOMのオブジェクトのプロパティがどうなっているのかを見ればわかります。

上で説明したように, プロパティはそのオブジェクトの性質を表すものです。 DOMにおいて, ブラウザのウィンドウに表示されるドキュメントを表すのがdocumentオブジェクトでした。

documentオブジェクトは次のようなプロパティをもちます(DOMでそう決まっています)。 ここにあげたプロパティは一部だけで, このほかにもあります。

あるオブジェクトのもつプロパティを確認してみるには, 「document.<プロパティ名>」という形式を使えばよいのです。 たとえばdocument.titleでこのドキュメントのタイトル, document.URLでこのドキュメントのURL(アドレス)がわかります。

HTMLにすると, たとえば次のような具合になります(図A-3)。

<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
</head>
<body>
<p>
document.URLでURLがわかります。 
<script type="text/javascript">
   document.write("このドキュメントのURLは「" + document.URL  + "」です。 ");
</script>
</p>
</body>
</html>
図A-3 documentのプロパティ(URL)を表示

ところで, 上にあげたdocumentオブジェクトのプロパティの一覧にあるforms[]は何でしょうか? これもdocumentのもつプロパティなのですが, ドキュメント内に含まれるフォームから成る配列になっているのです。

URLとかタイトルとかが「プロパティ(属性)」というのはわかりますが, 「フォームの配列」がプロパティとはどういうことでしょうか? じつは, オブジェクトは別のオブジェクトをプロパティとして持つことができるのです。 ドキュメントの中には, フォームが書かれることがあります。 そのフォームを表現するのにFormという種類のオブジェクトを使うのです。 そして, ドキュメントの中にフォームは複数はいることができるので, documentのformプロパティはFormオブジェクトから成る配列なのです(つまり, 配列もオブジェクトだというわけです)。

具体的にどう使うかというと(これは実はもう前に使ったのですが)document.forms[0], document.forms[1], ...でドキュメント内に含まれる最初のフォーム, 2つ目のフォーム, ...を表します。

オブジェクトのプロパティとしては, オブジェクトを持つことができます(そして, そのオブジェクトのプロパティとして, またまたオブジェクトを持つことができるわけです)。 なかなかピンと来ないでしょうが, 使い方を覚えればそのうち慣れるでしょう。

同じようにして, (documentのプロパティである)フォームを表すオブジェクトFormも(これ自体オブジェクトなので)下のようなプロパティを持ちます(ここにあげたのは一部)。

このプロパティを使った例が次のコードです(図A-4)。

<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
</head>
<body>
<p>
<form>
  <table align="center" width="600">
  <tr>
    <td><input type="button" name="saiten" value="さいてん"</td>
    <td>せいかい<input type="text" name="seikai" size="3"></td>
    <td>まちがい<input type="text" name="machigai" size="3"></td>
    <td><input type="button" name="again" value="つぎへ"</td>
  </tr>
  </table>
</form>
<hr>
<p>
document.forms[i].<プロパティ>で, (0から数えて)i番目のフォームのプロパティにアクセスできます。 たとえば, document.forms[0].lengthをみることにより, この上のフォームには, 
<script type="text/javascript">
   document.write(document.forms[0].length);
</script>
個の要素があることがわかります。 
</p>
</body>
</html>
図A-4 Formオブジェクトのプロパティの表示

これで, 次の式の意味するところがおわかりいただけたでしょう。

  document.forms[0].elements[0].value

これは「ウィンドウ内にロードされたHTMLページを表すdocumentオブジェクトの(プロパティである)formsという名前の配列の0番目の要素であるオブジェクトの(プロパティである)elementsという名前の配列の0番目の要素であるオブジェクトの(プロパティである)valueの値」を表していたわけです。

平たく言えば, 「HTMLのドキュメントに入っている, 最初のフォームの最初の要素(コントロール)の値」ということなのですが, DOMに従って表現すれば上のようになります。

さて, 同じ値を表すのに, 先のプログラムでは, 次のような表現も用いました。

  document.yomiganaForm.kanji.value

これは, 「documentオブジェクトのプロパティであるyomiganaFormのプロパティであるkanjiのvalueというプロパティの値」を意味します。 yomiganaFormというdocumentのプロパティは, <form name="yomiganaForm">とname属性を指定したときに自動的に作られたものです。 その値はforms[0]と同じで, そのフォームに含まれる要素(テキスト領域やボタンなど)を表すオブジェクトからなる配列になります。

document.yomiganaForm.kanjiは, このyomiganaFormという名前のFormオブジェクトのkanjiという名前のプロパティです。 すでに見たように, このプロパティもオブジェクトで, この場合はテキスト入力欄を表すオブジェクト(textオブジェクト)になります。

メモ

DOMのdocumentオブジェクトの上にはwindowオブジェクトがあります。 上の表現(たとえばdocument. yomiganaForm.kanji.value)にはwindowは出てきていません。 これは, ブラウザウィンドウ内にあるものはすべてwindowオブジェクトの子供になるので, windowは省略してもよいことになっているからです。 つまり, 次のように書いても同じことになります。

window.document.yomiganaForm.kanji.value

オブジェクトと配列 ── 配列もオブジェクト

配列についてもう少し詳しく見ておきましょう。 上で書きましたが, 配列もそれ自体オブジェクトなのです。

再び次の表現を見ましょう。

  document.forms[0].elements[0].value

document.formsはdocumentオブジェクトのformsプロパティを表しています。 これ自体Formオブジェクトというフォームを表すオブジェクトからなる配列です。

document.forms[0]はformsというプロパティの最初の要素を表しており, これはFormsオブジェクトになります。

document.forms[0].elementsはFormオブジェクトのプロパティですが, これまたオブジェクトで, 今度はテキスト入力欄やボタンなどフォームの要素から成る配列になります。

document.forms[0].elements[0]は, Lesson 6の例では漢字文字列のはいるkanjiという名前のテキスト入力欄でしたから, textオブジェクトになります。 ほかのフォームの場合には, buttonになったりすることもあります。 上のforms[]配列の要素はすべてFormオブジェクトでしたが, elements[]配列の要素はtextオブジェクトだったり, buttonオブジェクトだったりするわけです。

配列の要素の参照は, じつは配列オブジェクトのプロパティを参照しているということになるわけです。 x[0]はxという名前の配列の0というプロパティのことなのです。 同様に, gKanjiYomi["山"]はじつは, gKanjiYomiという配列の"山"プロパティの値という意味だったのです。 漢字コードの問題があるので, 今のところ「gKanjiYomi.山」のようにすることは多くの環境ではできませんが, たとえば次の2つの文は同じことになります。

  romajiYomi["ya"] = "や";
  romajiYomi.ya = "や";

これまでは, JavaScript以前に存在していたプログラミング言語の言葉を使って説明してきましたが, JavaScriptでは「配列」を「オブジェクトとそのプロパティ」という概念を使って表現しているというわけです。

メモ

もう一度繰り返しますが, 配列もひとつのオブジェクトです。 JavaScriptの配列には, プロパティとして同じ種類のものだけではなく違う種類のものを記憶しておくこともできます。 たとえば, elements[0]にテキスト入力欄を表すオブジェクト(textオブジェクト)をelements[1]にボタンを表すオブジェクト(buttonオブジェクト)を記憶することができます。

なお, 多くの言語では配列をこのようには扱ってはいません。 そして, ひとつの配列には同じ種類のデータ(整数なら整数だけ, 文字なら文字だけ)しか記憶できないので, 他の言語を扱うときには注意が必要でしょう。

このあたりの話は, とくに最初のうちはチンプンカンプンかもしれません。 しばらくは棚上げしておいても全然差し支えありません。 忘れては困るのはelement[2]あるいはelement["name"]のようにすれば, 配列の要素にアクセスできるということです。

オブジェクトの動作 ── メソッド

オブジェクトを特徴づけるもうひとつは「メソッド」です。 これはオブジェクトがどのような動作をできるか, どのような機能をもつかを表現するものです。

この言葉はきちんと説明はしませんでしたが, すでにTextbookで何度か登場しました。 たとえば, もう何回も登場した次の文ではdocumentオブジェクトのメソッドを使っています。

  document.write("<h2>けいさんもんだい</h2>\n");

write()というのがdocumentオブジェクトのもつメソッドです。 documentオブジェクトはHTMLドキュメントを表現するもので, document.write()で「このHTMLドキュメントに, 引数として指定した文字列を書きなさい(表示しなさい)」ということになるわけです。

confirm()とかprompt()というのも実はオブジェクトに属するメソッドです。 これらのメソッドはwindowオブジェクトに属しています。 現在表示されているブラウザウィンドウの上に新しいウィンドウ ── ダイアログボックス ── が出てくるので, windowオブジェクトのメソッドというのは自然な話でしょう。 したがって, 省略せずにきちんと書くなら次のように表記することになります。

    window.confirm("おはようございます。 ");
    kotae = window.prompt(mondai, "");

さて, このほかにもMath.random()とか, Math.floor()などというのもありました。 じつは, Mathはwindowオブジェクトのプロパティです。 それでrandom()はwindowオブジェクトのプロパティであるMathオブジェクトに属するメソッドというわけです。 したがって, Lesson 13で定義した関数randomInt()は次のようにも書くこともでます。

  function randomInt(i) {
    // 1以上i以下の整数を返す
    return( window.Math.floor(window.Math.random()*i) + 1 );
  }

もうひとつ例を見ましょう。 次の文はLesson 13の計算問題の最終版で登場した例です。

  document.keisanMondai.elements[0].focus(); // 最初の問題に移動

この文は「(windowオブジェクトのプロパティの)documentオブジェクトのkeisanMondaiという名前のプロパティ(であるFormオブジェクトの)プロパティであるelementsというオブジェクトの最初の要素のメソッドであるfocus()」を呼び出します。 これを呼び出すことによってフォーカスがその要素(この場合にはテキスト入力欄)に移動します。 このことから, テキスト入力欄にはfocus()というメソッドが備わっていることがわかります。

メモ

Lesson 13で次のような代入文を使ったのを覚えているでしょうか? document. keisanMondaiと何度も繰り返さずに, この部分をfと表記するために用いました。

  var f = document.keisanMondai; // form

これは, fという変数にdocumentのkeisanMondaiというプロパティ, つまりFormオブジェクトを代入したことになります。 JavaScriptの変数にはどのようなオブジェクトを代入することもできるわけです。 このようにfに途中のオブジェクトを記憶しておくことによって, 次のようにdocumentから書き下さずに短く表現することができるわけだったのです。

f.elements[i].value
f.again.focus()

f.again.focus()は, Formオブジェクトのagainというプロパティであるbuttonオブジェクトのメソッドfocus()の呼び出しです。

イベントの処理 ── イベントハンドラ

JavaScriptのオブジェクトは, プロパティとメソッドのほかに, もうひとつ「イベントハンドラ(event handler)というおもしろいものをもっています。 これは(ちょっとメソッドと似ていますが)何かそのオブジェクトに関連した出来事 ── イベント ── が起こったときに何らかの処理を起動できる仕組みです。

じつはこれもすでに計算問題の最終版に出てきていました。 JavaScriptで出力されるコードに次のようなものがありました。

<input type="button" name="again" value="つぎへ" onclick="location.reload();">

このonclick=がこのボタンのイベントハンドラの指定です。 前に説明したように, このボタンがクリックされたときにlocation.reload()というlocationオブジェクトのreload()メソッドが実行されるわけです。

どのようなイベントハンドラが使えるかは, 各オブジェクトごとに定義されています。

JavaScriptとDOMとブラウザの動作

さて, ブラウザとJavaScriptの仲介役であるDOM(Document Object Model)の面白くそして便利なところは, DOMのオブジェクトのプロパティとブラウザのウィンドウの動作が密接に結びついているところです。 Lesson 13の次の例を思い出してください。

        if (f.elements[i].value == eval(gMondaiKioku[i]) ) { // 正解
          f.elements[i].value += " ○";
          seikai++;
        }
        else {    // まちがい
          f.elements[i].value += " ×";
          machigai++;
        }

これは正解に○, 間違い×をつけているところですが, このようにtextオブジェクト(入力欄を表す)に値を代入するだけで, これがブラウザの画面の表示と直結していて, 入力欄に表示されている文字列も即座に変わるようになっています。

逆に, 利用者がテキスト入力欄に文字列を記入したり, メニュー項目を選択したりすると, JavaScriptのオブジェクトのプロパティの値も変わるというわけです。

このように, オブジェクトのもつプロパティがブラウザの表示と直に結びついているわけです。

JavaScriptはいわば「ブラウザ処理用の言語」のような生い立ちでできたものなので, このようにブラウザと強い結びつきをもっています。 ほかの言語, たとえばPerlやJavaなどはこのような性質はもっていません。 この中でJavaは根っからのオブジェクト指向言語で, プロパティやメソッドなどの概念をJavaScriptとある程度似たように使っていますが, ブラウザとこれほど密接な結びつきはありません。 Perlにもバージョン5からオブジェクト指向の機能が付加されましたが, ブラウザに相当するようなものはもっていません。

まとめ

この付録ではこれまで見てきたいろいろな概念を, やや理論的な観点から見直しました。 突然話が概念的になったので, 難しいところもあったかもしれませんが, JavaScript言語の裏にある, 「思想」とでもいうものを, ある程度感じていただければ, それでこの付録の目的は達せられたことになります。

オブジェクト指向に関連する概念

DHC-オンライン講座
文系の人にもわかる プログラミング入門
付録