5.3 インスタンス

(1/1)
インスタンス
DateオブジェクトArrayオブジェクトなど、JavaScriptにあらかじめ用意されたオブジェクトからnew演算子を使って生成した新しいオブジェクトのことをインスタンスと呼ぶ。
JavaScriptの配列は、じつは Arrayオブジェクトのインスタンスであり、あらかじめ複数のプロパティメソッドが用意されている。

目次

サンプル・プログラム

Dateオブジェクト

JavaScriptで日付処理を行うときにDateオブジェクトを利用するが、異なる2つの日付を扱いたい場合には、Dateオブジェクトを2つ用意する必要がある。Dateオブジェクトから別のDateオブジェクトを生成したものをインスタンスと呼ぶ。JavaScriptでは new演算子を使ってインスタンスを生成する。

  47:     //今日の日付
  48:     let today = new Date();
  49:     document.getElementById('today').innerHTML = '今日  '
  50:         + today.getFullYear().toString() + '年'
  51:         + (today.getMonth() + 1).toString() + '月'
  52:         + (today.getDate()).toString() + '日';
  53: 
  54:     //1週間前の日付
  55:     let lastWeek = new Date();
  56:     lastWeek.setDate(lastWeek.getDate() - 7);       //7日前にする
  57:     document.getElementById('lastWeek').innerHTML = '1週間前 '
  58:         + lastWeek.getFullYear().toString() + '年'
  59:         + (lastWeek.getMonth() + 1).toString() + '月'
  60:         + (lastWeek.getDate()).toString() + '日';

プログラム "date1.html" は、今日の日付のインスタンスを変数 today に、先週の日付のインスタンスを変数 last_week に代入する。
new演算子によってDateオブジェクトのインスタンスを生成するが、このときに使うオブジェクト名と同じ Date はメソッドの一種で、そのインスタンスを初期化する作用もありコンストラクタ と呼ぶ。Dateコンストラクタの場合、引数を何も指定しないと現在日時を初期値とするDateオブジェクトを生成する。
getFullYear はオブジェクト(インスタンス)の西暦年を取得するメソッド、getMonth は月を取得するメソッド(1月が0から始まることに注意)、getDate は日付を取得するメソッドである。

setDate メソッドは、オブジェクトの日付を設定するもので、ここでは現在日付から7を減じた(1週間前)値を設定している。たとえば8月2日から算術的に7を減じると-5日になってしまうが、Dateオブジェクトの中では月や年の再計算が行われ、カレンダーとして正しい年月日が表示される。

Arrayオブジェクト

「4.3 配列」のコラムで、配列はオブジェクトの一種だと書いた。ここでは、配列が Arrayオブジェクトであることを見ていこう。
5.1 配列とオブジェクト」で紹介した方法で1次元配列 arr を初期化するには、下記のようにする。

  78:     //配列だと‥‥
  79:     /**
  80:     let arr = new Array(2117, 3602, 5524, 1059, 1432, 2807, 2340, 445, 4598, 3518);
  81:     **/

この初期化方法は、じつは Arrayオブジェクトのインスタンスを生成している。
下記のように、new演算子を使ってArrayオブジェクトのインスタンスを生成することで、まったく同じ動作となる。

  75:     //Arrayオブジェクトだと‥‥
  76:     let arr = new Array(2117, 3602, 5524, 1059, 1432, 2807, 2340, 445, 4598, 3518);

lengthプロパティ

Arrayオブジェクトには複数のプロパティやメソッドが備わっている。
たとえば、lengthプロパティは、Arrayオブジェクトの要素数を保持している。このプロパティを参照し、要素の数を表示する。

  55:         html +'<tr><td>要素の数:' + arr.length + '</td></tr>\n';

なお、length プロパティを使い、forEachループの代わりに forループにすることもできるが、読みやすいログラムに反するのでここでは取り上げない。

sortメソッド

Arrayオブジェクトの要素を並び替えるには、sortメソッドを用いる。

  82:     //並び替え
  83:     arr.sort();

sortメソッドは要素を String型に変換してから辞書順並び替えを行うので、Number型に対しては期待していたとおりの結果にならない。
そこで、引数にユーザー定義の比較関数を加えてやる。

  61: /**
  62:  * 比較関数(小さい順) -- sortから呼び出す
  63:  * @param   Number a, b  比較する値
  64:  * @return  Number 比較結果
  65: */
  66: let cmp1 = function compare1(a, b) {
  67:     return a - b;
  68: }

  91:     //並び替え(小さい順)
  92:     arr.sort(cmp1);

ユーザー定義関数 compare1 は、2つの引数を比較し、a < b のときは負数を、a > b のときは正数を返すことで、要素の小さい順に並べ替えを行うことができる。なお、a == b のときの sortメソッドの動作は不定である。
大きい順に並び替えたければ、returnの式を反対にしてやればいい。
sortメソッドの引数は変数の形で渡す必要があるので、function定義時に変数 cmp1 に代入している。

比較関数は、下記のように無名変数を用いて引数に直接渡すことができる。

  82:     //並び替え:比較関数は無名関数
  83:     arr.sort(function(a, b) {
  84:         return a - b;
  85:     });

filterメソッド

Arrayオブジェクトの要素を抽出するのに、filterメソッドが用意されている。sortメソッド同様、引数に抽出用関数を渡してやる。引数が抽出条件を満たすときはtrueを、満たさない場合はfalseを返す関数を用意する。filterメソッドの戻り値は、抽出した要素を集めた Arrayオブジェクトである。

  82:     //抽出:2000未満の要素抽出
  83:     let arr2 = arr.filter(function(a) {
  84:         return a < 2000;
  85:     });

Arrayオブジェクトには、これ以外にも、要素を検索する find、要素を検索して添え字を返す indexOf、Arrayオブジェクトかどうか調べる isArray などのメソッドがある。

このように、プロパティやメソッドが用意されていることから、JavaScriptの配列は、他のプログラミング言語で言うところの配列とは異なり、Arrayというオブジェクトであることが理解していただけたことと思う。

mapメソッドと他のループ処理の比較

以前、「forEachメソッドを紹介したが、Arrayオブジェクトに対してはもう1つ、mapメソッドというループ処理がある。これまで照会したループ処理との違いを見ておこう。

  49:     //元になる配列
  50:     let a = [0, 1, 2, 3, 4];
  51:     a[5] = 5;
  52:     a[2.5] = 2.5;
  53: 
  54:     //forループ
  55:     let b = [];
  56:     for (let i = 0i < a.lengthi++) {
  57:         b[i] = a[i+ 1;
  58:     };
  59: 
  60:     //for...inループ
  61:     let c = [];
  62:     for (const i in a) {
  63:         c[i] = a[i+ 2;
  64:     };
  65: 
  66:     //forEachメソッド
  67:     let d = [];
  68:     a.forEach(function(val, i) {
  69:         d[i] = a[i+ 3;
  70:     });
  71: 
  72:     //mapメソッド
  73:     let e = a.map(function(val, i) {
  74:         return val + 4;
  75:     });
  76: 
  77:     //一覧表を作成する.

mapメソッドの特徴は、コールバック関数の戻り値を返し、新しいArrayオブジェクトに代入することができる点にある。元の配列を残して新しい配列を生成したいような場合は、mapメソッドを使って簡明に書くことができる。

また、元になる配列 a に対し、わざと、添字5の要素と、添字2.5の要素を代入した。添字5の方は、どのループでも取り扱っているのだが、添字2.5を捉えているのは for...inループだけである。
これは、添字2.5はオブジェクトとして認識され、元になる配列 alengthプロパティが加算されないためである。
以前にも説明したように、オブジェクトに対してループ処理する場合は、for...inループを適用する。そして、for...inループは処理の順序が、必ずしも添字の順序ではないことに注意したい。
mapメソッドを使ったプログラム例を紹介しよう。
元号を時刻表のように並べる

 316: /**
 317:  * 元号を表示しやすいように配列に格納する.
 318:  * @param   Array eras[] 元号を格納する配列
 319:  * @return  int 格納した元号の数
 320: */
 321: function getEras2(eras) {
 322:     let cnt = 0;
 323: 
 324: //  Object.keys(AD_ERA_LIST).forEach(function(yyyymmdd) {
 325:     Object.keys(AD_ERA_LIST).map(function(yyyymmdd) {
 326:         //開始年月日
 327:         let hh = Number(yyyymmdd.substr(0, 2));     //時に相当(西暦上2桁)
 328:         let mm = Number(yyyymmdd.substr(2, 2));     //分に相当(西暦下2桁)
 329:         //配列の2次元目を生成
 330:         if (! Array.isArray(eras[hh])) {
 331:             eras[hh] = new Array(100);
 332:         }
 333:         eras[hh][mm] = AD_ERA_LIST[yyyymmdd];
 334:         cnt++;
 335:     });
 336: 
 337:     return cnt;
 338: }

 340: /**
 341:  * 時刻表を作成する.
 342:  * @param   Array eras[][] 元号配列
 343:  * @return  String 表示テキスト(HTML)
 344: */
 345: function gengoTimeTable(eras) {
 346:     let html = `
 347: <caption>${CAPTION1}</caption>
 348: <tr><td colspan="2" class="index">${CAPTION2}</td></tr>
 349: `;
 350: 
 351: //  eras.forEach(function(era1, hh) {
 352:     eras.map(function(era1, hh) {
 353:         if ((hh < 24&& (era1.length > 1)) {
 354:             html +'<tr>\n<td class=\"hour\">' + hh + '</td>\n<td class=\"minuite\">';
 355: //          era1.forEach(function(era, mm) {
 356:             era1.map(function(era, mm) {
 357:                 let m2 = ('00' + String(mm)).slice(-2);
 358:                 if (era !'') {
 359:                     let style = (era.length > 2? ' style="zoom:0.6;"' : '';
 360:                     html +'<ruby>' + m2 + '<rt' + style + '>' + era + '</rt></ruby>\n';
 361:                 }
 362:             });
 363:         }
 364:     });
 365: 
 366:     return html;
 367: }

コラム:HTMLファイルもまたオブジェクト

HTMLのイラスト
プロパティは変数に似ているが、そのインスタンス内でしか通用しない点が異なる。オブジェクトの外で参照/代入するときは、かならず、インスタンス名.プロパティ名と書く。

メソッドと関数の関係も同様で、メソッドはそのインスタンス内でしか通用しない。外部からメソッドを利用する場合は、かならず、インスタンス名.メソッド名と書く。
JavaScriptでは、自分自身が書かれているファイル(HTMLファイル)をオブジェクトとして認識している。
つまり、document は自分自身が書かれているファイル(HTMLファイル)そのものであり、getElementByIdメソッドはそこからID名で指定されたオブジェクトを取り出すことを意味する。innerHTMLプロパティは、対応するオブジェクトのHTML文そのものを指し示している。
(この項おわり)
header