ブログの説明

学校に通わないで学んだことを記しています。間違っているところが何かありましたらご指摘下さると幸いです。コメントに対する返信が遅れる可能性があります。その場合は申し訳ありません。

このブログではサイドバーに広告を表示しています。このブログ内の投稿記事を検索するには右上の拡大鏡のアイコンを、アーカイブやラベル付けから投稿記事を閲覧するには左上の三重線のアイコンをクリックして下さい。

数式の表示にはMathJaxを利用させていただいています。数式の表示のためにJavaScriptが有効である必要があります。そうでない場合、訳の分からないLatexのコードが表示されます。幾何学図形やチャートの表示にはHTML5 CanvasやGoogle Chartを使用しています。その表示のためにもJavaScriptが有効である必要があります。

JavaScriptでオブジェクトを作成する方法

オブジェクト指向言語には大きく分けてクラス・ベースのものとプロトタイプ・ベースのものとがある。JavaScriptはプロトタイプ・ベースのオブジェクト指向としての特徴を備えているとされている。

オブジェクトとは、関連する変数や函数をまとめて名前を付けた参照型の変数のことであり、オブジェクト型変数とも呼ばれている。

JavaScriptでプログラマーが独自にオブジェクトを作るには、

  1. オブジェクト・リテラル、
  2. ファクトリ函数、
  3. Object()コンストラクター、
  4. コンストラクター函数、
  5. クラス構文、
  6. 継承
などを用いる方法がある。それぞれについて見ていく。ただし継承についてはこの投稿では触れない。

オブジェクト・リテラル

関連する変数や函数であるプロパティの定義を列挙したオブジェクト・リテラルを変数に代入するとJavaScriptでは簡単にオブジェクトを作ることができる。この方法はオブジェクト・イニシャライザーとも呼ばれている。

ただしこの方法では1つのオブジェクト・リテラルから1つのオブジェクトしか作ることができない。

オブジェクト・リテラルの構文はJSON(JavaScript Object Notation)やPythonの辞書型のそれに似ている。すなわち「{キー:値,キー:値,...}」のようにコーディングし、そのオブジェクト・リテラルを変数に代入するだけでオブジェクトが1つ作られる。オブジェクト・リテラルではこのキーがプロパティ名やメソッド名になる。

オブジェクト・リテラルは次のようにコーディングする。

キーワード 変数名 = {
   プロパティ名1 : 値,
   プロパティ名2 : 値,
   プロパティ名3 : 値
};

キーワードにはletかconstかvarを指定することができる。

プロパティの値に函数式を与えるとそのプロパティはメソッドになる。メソッドは特別な値を持ったプロパティ。メソッドはコード・プロパティとも呼ばれることがある。

キーワード 変数名 = {
   プロパティ名 : 値,
   メソッド名 : function(仮引数){} // 函数式
};

変数に代入されるかプロパティの値に与えられる函数の定義方法は函数式とか函数リテラルと呼ばれている。それに対して独立した函数の定義方法は函数宣言とか函数文と呼ばれている。函数式の式は英語ではan expression。

函数宣言ではその函数に固有の名前(識別子)を付けるが、函数式に使われるのは名前を付けない匿名函数か矢印函数。ただし函数ブロック内でその函数を再帰的に呼び出すために匿名函数に便宜的に名前を付けることがある。

仮引数というのはその函数が呼び出されるときに一緒に括弧内に渡す値を受け取るように定義された変数であり、パラメーターとも呼ばれている。数学と違って計算機科学での変数はデータを保存する記憶領域を暗に指している。

オブジェクト・リテラルによって作成したオブジェクトはプレイン・オブジェクトと呼ばれることがある。

オブジェクトを定義しているコード・ブロックの中で定義したプロパティをその外から参照するには「オブジェクト名.プロパティ名」のようにドット演算子を用いる。

プロパティに値を設定するには次のようにコーディングする。

オブジェクト名.プロパティ名 = 値;

メソッドを呼び出すには次のようにする。

オブジェクト名.メソッド名(引数);

次に例として挙げるコードは、オブジェクト・リテラルによってオブジェクトを定義し、それをcircleという変数に代入してcircleというオブジェクトを作成し、そのオブジェクトの構成要素であるプロパティとメソッドにメッセージを送り、色違いの3つの円をHTMLドキュメント上に描くもの。

<canvas id="ol_circle" width="300" height="150"></canvas>
<script>
// オブジェクトを作成
const circle = {
   radius : 30, // 半径
   line_width : 5, // 線の太さ
   stroke_color : 'blue', // 線の色
   fill_color : 'skyblue', // 塗りつぶす色
   // 円を描くメソッド(canvas要素ID、水平座標、垂直座標)
   draw : function(canvas_id,x,y) {
      // HTML5 Canvasの2DコンテキストのAPIを利用
      const canvas = document.getElementById(canvas_id);
      const ctx = canvas.getContext('2d');
      ctx.beginPath(); // パスを初期化
      // 円のパス(水平座標、垂直座標、半径、始点、終点)
      ctx.arc(x,y,circle.radius,0,Math.PI*2);
      ctx.closePath(); // パスを閉じる
      ctx.lineWidth = circle.line_width; // 線の太さ
      ctx.strokeStyle = circle.stroke_color; // 線の色
      ctx.stroke(); // 線を描く
      ctx.fillStyle = circle.fill_color; // 塗りつぶす色
      ctx.fill(); // 塗りつぶす
   }
};

// メソッドを呼び出す
circle.draw('ol_circle',60,70);
   
// 円の色を再設定
circle.stroke_color = 'orange'; // 線の色
circle.fill_color = 'yellow'; // 塗りつぶす色

// その右に円を更に描く
circle.draw('ol_circle',130,70);

// 円の色を再々設定
circle.stroke_color = 'red'; // 線の色
circle.fill_color = 'pink'; // 塗りつぶす色

// 更にその右に円を描く
circle.draw('ol_circle',200,70);
</script>

このコードをHTMLのbody要素の間に埋め込んでウェブ・ブラウザで読み込むと次のような3つの円が描かれるはず。

このウェブブラウザはHTML5 CanvasかJavaScriptに対応していません。

描かれた円は3つだが、作ったオブジェクトはただ1つ。定義したcircleオブジェトのdrawメソッドを呼び出して1つの円を描いた後、色のプロパティを設定し直して再度drawメソッドを呼び出して描画することによって異なる色の3つの円を描いた。

ちなみに、HTML5 Canvasでは.clearRect()メソッドを用いて明示的に消去しないかぎり、何度描き直しても前に描いたものはクリアされずに残る。

ファクトリ函数

ファクトリ函数はオブジェクトを返り値に持つ函数であり、オブジェクト・リテラルをその返り値に与える構文によって定義される。

オブジェクト・リテラルでは単体のオブジェクトしか作成することができないのに対し、ファクトリ函数ではオブジェクトを量産することができる。

同じオブジェクトを複数作成したい場合、その数だけオブジェクト・リテラルを記述しなくてもその作業を函数にやらせてしまえばいいというのがファクトリ函数の考え方。

ファクトリ函数の構文は次のとおり。函数がオブジェクト・リテラルを包み込むような構造をしている。

function 函数名(仮引数){
   キーワード 変数名 = {
      プロパティ名1 : 値,
      プロパティ名2 : 値,
      プロパティ名3 : 値
   };
   return 変数名;
}

キーワードにはletかconstかvarを指定することができる。

次のようにコーディングすることもできる。こちらのほうが一般的。

function 函数名(仮引数){
   return {
      プロパティ名1 : 値,
      プロパティ名2 : 値,
      プロパティ名3 : 値
   };
}

C++やJavaのような言語にはオブジェクトのプロパティへのアクセス制御を行うアクセス修飾子と呼ばれるものがある。

アクセス演算子にはprivateとpublicとprotectedとが一般的にある。private(プライベート)は外部からのアクセスを禁じ、public(パブリック)は外部からのアクセスを許可する。protected(プロテクテド)は継承されたオブジェクトからのアクセスだけを許可する。

ところが、JavaScriptにはアクセスを制御するためのアクセス修飾子がない。けれども、ファクトリ函数では次のようにすることによってプロパティのアクセス制御を可能にし、オブジェクトのカプセル化を実装することができる。

そのためにはプロパティを函数内の通常の変数として扱い、letやvarというキーワードを付けてreturnキーワードより前に並べ、returnキーワード後のオブジェクト・リテラルのコード・ブロック内には各変数にアクセスするためのゲッター(取得者)とセッター(設定者)と呼ばれるメソッドの定義を並べる。例えば次のように。

function 函数名(仮引数){
   // プライベート
   let 変数名1 = 値;
   let 変数名2 = 値;
   let 変数名3 = 値;
   return {
      // パブリック
      ゲッター名1 : () => 変数名1,
      ゲッター名2 : () => 変数名2,
      ゲッター名3 : () => 変数名3,
      セッター名1 : 仮引数1 => 変数名1 = 仮引数1,
      セッター名2 : 仮引数2 => 変数名2 = 仮引数2,
      セッター名3 : 仮引数3 => 変数名3 = 仮引数3,
      メソッド名 : function(仮引数){}
   };
}

このようにすると、returnキーワードの後のオブジェクト・リテラルの部分だけがパブリックになって外部からアクセスでき、そうでないローカル変数の分はプライベートになって外部からは隠蔽される。

このコードで用いた「() =>」は矢印函数とも呼ばれているもの。アロー函数とも呼ばれている。通常の匿名函数「function(){}」よりも簡略にコーディングできるけれども動作する上で制約がある。矢印函数ではthisキーワードが有効でないので要注意。

矢印函数を使わずに匿名函数を使った場合には次のようになる。

function 函数名(仮引数){
   // プライベート
   let 変数名1 = 値;
   let 変数名2 = 値;
   let 変数名3 = 値;
   return {
      // パブリック
      ゲッター名1 : function(){return 変数名1},
      ゲッター名2 : function(){return 変数名2},
      ゲッター名3 : function(){return 変数名3},
      セッター名1 : function(仮引数1){変数名1 = 仮引数1},
      セッター名2 : function(仮引数2){変数名2 = 仮引数2},
      セッター名3 : function(仮引数3){変数名3 = 仮引数3},
      メソッド名 : function(仮引数){}
   };
}

ここで用語について少し注釈。JavaScriptではゲッターとセッターというメソッドが共にアクセサー・プロパティと呼ばれている。通常のプロパティはデータ・プロパティとも呼ばれており、メソッドはコード・プロパティと呼ばれることがある。いずれも広義のオブジェクト・プロパティ。

ファクトリ函数を呼び出してオブジェクトを作成する際にはnewキーワードを用いない。ファクトリ函数を呼び出してその返り値を変数に代入するだけで複数のオブジェクトを作り出すことができる。この変数名がオブジェクト名になる。

キーワード 変数名 = ファクトリ関数名(引数1,引数2);

次のコードではCircleと名付けたファクトリ函数を用いて円を描くためのオブジェクトを定義している。円を描く線の色と円を塗りつぶす色を引数にしてこのファクトリ函数を呼び出すと、円を描くためのプロパティとメソッドを持ったオブジェクトが出力される仕組み。

<canvas id="ff_circle" width="300" height="200"></canvas>
<script>
// Circleオブジェクトを定義するファクトリ函数
function Circle(strokeColor,fillColor){
   // プライベートなプロパティ(ローカル変数)
   let radius = 30; // 円の半径
   let line_width = 5; // 線の太さ
   let stroke_color = strokeColor || 'blue'; // 線の色
   let fill_color = fillColor || 'skyblue'; // 塗りつぶす色
   
   // オブジェクト・リテラルを返す
   return {
      // パブリックなゲッター
      getRadius : () => radius,
      getLineWidth : () => line_width,
      getStrokeColor : () => stroke_color,
      getFillColor : () => return fill_color,
      
      // パブリックなセッター
      setRadius : arg => radius = arg,
      setLineWidth : arg => line_width = arg,
      setStrokeColor : arg => stroke_color = arg,
      setFillColor : arg => fill_color = arg,
         
      // 円を描くパブリックなメソッド
      //(canvas要素ID、水平座標、垂直座標)
      draw : function(canvas_id,x,y){
         // HTML5 Canvasの2DコンテキストのAPIを利用
         const canvas = document.getElementById(canvas_id);
         const ctx = canvas.getContext('2d');
         ctx.beginPath(); // パスの初期化
         // 円のパス(水平座標、垂直座標、半径、始点、終点)
         ctx.arc(x,y,radius,0,Math.PI*2);
         ctx.closePath(); // パスを閉じる
         ctx.lineWidth = line_width; // 線の太さ
         ctx.strokeStyle = stroke_color; // 線の色
         ctx.stroke(); // 線を描く
         ctx.fillStyle = fill_color; // 塗りつぶす色
         ctx.fill(); // 塗りつぶす
      }
   };
}

// ファクトリ函数を呼び出してオブジェクトを作成
const circle1 = Circle(); // 引数なし
const circle2 = Circle('orange','yellow');
const circle3 = Circle('red','pink');

// drawメソッドを呼び出して円を描く
circle1.draw('ff_circle',60,60);
circle2.draw('ff_circle',130,60);
circle3.draw('ff_circle',200,60);

// 線の色と塗りつぶす色をセッターで再設定
circle1.setStrokeColor('black');
circle2.setStrokeColor('green');
circle3.setStrokeColor('saddlebrown');
circle1.setFillColor('grey');
circle2.setFillColor('lightgreen');
circle3.setFillColor('peru');

// 下隣の座標に円を描画
circle1.draw('ff_circle',60,130);
circle2.draw('ff_circle',130,130);
circle3.draw('ff_circle',200,130);
</script>

ファクトリ函数はそれを呼び出すごとにいくつでもオブジェクトを生成できるので、このコードでは3つのオブジェクトを生み出し、その上で円を塗りつぶす色のプロパティの値をアクセサーを用いて変えることにより色違いの計6つの円を描くようにコーディングした。

プロパティは外部から直接アクセスできないようにletキーワードを用いてオブジェクト・リテラルの外側で定義することによってプライベートにした。そしてgetとsetという接頭辞を付けた名前のアクセサーを各々のデータ・プロパティのために用意し、それらアクセサーを介してのみ各々のデータ・プロパティに外部からアクセスできるようにした。

このコードをHTMLのbody要素の間に埋め込んでウェブ・ブラウザで読み込むと次のように色違いの6つの円が描かれるはず。

このウェブブラウザはHTML5 CanvasかJavaScriptに対応していません。

Object()コンストラクター

newキーワードと共にObject()を用いるとオブジェクトを作ることができる。Object()の括弧内の引数に何も指定しないかnullやundefinedを指定した場合には空のオブジェクトが生み出される。

キーワード 変数名 = new Object();

キーワードにはletかconstかvarを用いる。

この手続きは他のオブジェクト指向言語では一般にインスタンス化と呼ばれている。例えばJavaでもこの際にnewキーワードを用いる。

コンストラクターとはインスタンス化と共に自動的に実行される特別な函数のこと。JavaScriptではコンストラクターとnewキーワードとは不可分の関係にある。

空のオブジェクトには次のようにしてプロパティとその値とを後から追加することができる。

変数名.プロパティ名 = 値;

プロパティの値に匿名函数や矢印函数の定義を与えるとそれはメソッドになる。

次のコードでは、circleという空のオブジェクトを作成し、その後にcircleオブジェクトのプロパティとメソッドを設定している。メソッドの定義では矢印函数を用いた。

<canvas id="ol_circle" width="300" height="150"></canvas>
<script>
// 空のオブジェクトを生成
const circle = new Object();

// 円の各種プロパティを設定
circle.radius = 30; // 円の半径
circle.line_width = 5; // 線の太さ
circle.stroke_color = 'blue'; // 線の色
circle.fill_color = 'skyblue'; // 塗りつぶす色
//円を描くメソッド(矢印函数)
circle.draw = (canvasId,x,y) => {
   // HTML5 Canvasの2DコンテキストのAPIを利用
   const canvas = document.getElementById(canvasId);
   const ctx = canvas.getContext('2d');
   ctx.beginPath(); // パスの初期化
   // 円のパス(水平座標、垂直座標、半径、始点、終点)
   ctx.arc(x,y,circle.radius,0,Math.PI*2);
   // 線の太さ
   ctx.lineWidth = circle.line_width;
   // 線の色
   ctx.strokeStyle = circle.stroke_color;
   ctx.stroke(); // 線を描く
   // 塗りつぶす色
   ctx.fillStyle = circle.fill_color;
   ctx.fill(); // 塗りつぶす
};

// drawメソッドを呼び出して円を1つ描く
circle.draw('oc_circle',60,60);

// 円の色を再設定
circle.stroke_color = 'orange';
circle.fill_color = 'yellow';

// 右隣に円を1つ描く
circle.draw('oc_circle',130,60);

// 円の色を再々設定
circle.stroke_color = 'red';
circle.fill_color = 'pink';

// その右隣に円を1つ描く
circle.draw('oc_circle',200,60);
</script>

作成したオブジェクトは1つだが、HTML5 Canvasを利用して円を描くdrawメソッドを3回呼び出し、プロパティを設定し直すことで色違いの円を3つ描くようにした。

このコードをHTMLのbody要素の間に埋め込んでウェブ・ブラウザに読み込むと次のように表示されるはず。

このウェブブラウザはHTML5 CanvasかJavaScriptに対応していません。

コンストラクター函数

コンストラクター函数も量産型のオブジェクトを定義する場合に用いることができる。コンストラクター函数ではパブリックなプロパティとパブリックなメソッドにthis.を付けて定義する必要がある。

function 函数名(仮引数){
   this.プロパティ名1 = 値;
   this.プロパティ名2 = 値;
   this.プロパティ名3 = 値;
   this.メソッド名 = function(仮引数){}
}

プロパティに外から直接アクセスできないようにするには、ファクトリ函数のときと同様にプロパティを通常のローカル変数にするためにその前にletかvarかconstかいずれかのキーワードを付ける必要がある。そしてその代わりにゲッターとセッターというアクセス用のメソッド(アクセサー)を定義し、それらのメソッド(アクセサー)を介してプロパティの参照と設定を行う。

function 函数名(仮引数){
   // プライベート
   let 変数名1 = 値;
   let 変数名2 = 値;
   let 変数名3 = 値;
   
   // パブリック
   this.ゲッター名1 () => 変数名1;
   this.ゲッター名2 () => 変数名2;
   this.ゲッター名3 () => 変数名3;
   this.セッター名1 (仮引数a) => 変数名1 = 仮引数a;
   this.セッター名2 (仮引数b) => 変数名2 = 仮引数b;
   this.セッター名3 (仮引数c) => 変数名3 = 仮引数c;
   this.メソッド名 = function(仮引数){}
}

letというキーワードと共に定義されているローカル変数は外から直接アクセスできないためにプライベートになる。このことはキーワードにvarやconstを用いても同様。

this.によって定義されているプロパティやアクセサーやメソッドは外から直接アクセスできるためにパブリックになる。

コンストラクター函数を定義したら、newキーワードと一緒に呼び出して変数に代入することでオブジェクトを作成できる。いわゆるインスタンス化。コンストラクター函数の定義内で用いられたthisキーワードが指し示すのがこの変数名であり、この変数名がオブジェクト名となる。

キーワード 変数名 = new コンストラクター関数名(引数1,引数2);

アクセサーなどのメソッドを呼び出す方法はこれまでと同様。

オブジェクト名.メソッド名(引数1,引数2);

次のコードではコンストラクター函数によってHTMLドキュメント上に円を描くためのオブジェクトの定義と作成を行っている。

<canvas id="cf_circle" width="300" height="120"></canvas>
<script>
// オブジェクトを定義
function Circle(strokeColor,fillColor){
   // プライベートな変数
   let radius = 30; // 円の半径
   let line_width = 5; // 線の太さ
   let stroke_color = strokeColor || 'blue'; // 線の色
   let fill_color = fillColor || 'skyblue'; // 塗りつぶす色

   // パブリックなゲッター
   this.getRadius = () => radius;
   this.getLineWidth = () => line_width;
   this.getStrokeColor = () => stroke_color;
   this.getFillColor = () => fill_color;

   // パブリックなセッター
   this.setRadius = arg => radius = arg;
   this.setLineWidth = arg => line_width = arg;
   this.setStrokeColor = arg => stroke_color = arg;
   this.setFillColor = arg => fill_color = arg;
      
   // 円を描くパブリックなメソッド
   //(canvas要素のID、水平座標、垂直座標)
   this.draw = function(canvasId,x,y,){
      // HTML5 Canvasの2DコンテキストのAPIを使う
      const canvas = document.getElementById(canvasId);
      const ctx = canvas.getContext('2d');
      ctx.beginPath(); // パスを初期化
      // 円のパス(水平座標、垂直座標、半径、始点、終点)
      ctx.arc(x,y,radius,0,Math.PI*2);
      ctx.lineWidth = line_width; // 線の太さ
      ctx.strokeStyle = stroke_color; // 線の色
      ctx.stroke(); // 線を描く
      ctx.fillStyle = fill_color; // 塗りつぶす色
      ctx.fill(); // 塗りつぶす
   }
}

// 個々のオブジェクトを作成(インスタンス化)
const circle1 = new Circle()
const circle2 = new Circle('orange','yellow');
const circle3 = new Circle('red','pink');

// 円を描くメソッドを使う
circle1.draw('cf_circle',60,60);
circle2.draw('cf_circle',130,60);
circle3.draw('cf_circle',200,60);

// 円の半径を再設定
circle1.setRadius(20);
circle2.setRadius(20);
circle3.setRadius(20);

// 少し下の座標に円を描画
circle1.draw('cf_circle',60,130);
circle2.draw('cf_circle',130,130);
circle3.draw('cf_circle',200,130);
</script>

コンストラクター函数の名前(函数の識別子)は通常の函数と見分けるために先頭を大文字にする慣例がある。したがってCircleとした。

コンストラクター関数の冒頭でletキーワードと共に宣言してあるローカル変数はプライベート。それらは外部からアクセスできない。そのことはvarやconstをキーワードに選んでも同じ。

this.が付けられているメソッドはパブリック。それらには外部からアクセスすることができる。

上記のコードでは円の半径を再設定するためにそのプロパティに直接アクセスするのではなくセッターというメソッドを利用している。

このコードをHTMLドキュメントのbody要素間に埋め込んでウェブ・ブラウザで読み込むと次のように色や大きさの異なる円が6つ描かれるはず。

このウェブブラウザはHTML5 CanvasかJavaScriptに対応していません。

クラス構文

クラス構文の実体はコンストラクター函数であるが、クラス・ベースのオブジェクト指向言語に慣れ親しんでいる人たち向けに採用された構文。

クラス構文は次のような書式に従う。

class クラス名{
   constructor(仮引数){
      this.プロパティ名 = 値;
      this.プロパティ名 = 値;
   }
   this.メソッド名 = function(仮引数){}
}

クラス構文でカプセル化を実装するには、すなわちデータ・プロパティへの直接のアクセスを禁じるには、次のようにデータ・プロパティ名に接頭辞として#(ハッシュ)を付けるハッシュ名を利用できる。

class クラス名{
   #プロパティ名1;
   #プロパティ名2;

   constructor(仮引数){
      this.#プロパティ名1 = 値;
      this.#プロパティ名2 = 値;
   }

   ゲッター名1(){return this.#プロパティ名1;}
   ゲッター名2(){return this.#プロパティ名2;}

   セッター名1(仮引数1){this.#プロパティ名1 = 仮引数1;}
   セッター名2(仮引数2){this.#プロパティ名2 = 仮引数2;}

   メソッド名(仮引数){}
}

クラス構文は内部的にはコンストラクター函数であるのでnewキーワードと共に呼び出してオブジェクトを作る。

キーワード 変数名 = new クラス名(引数);

クラス構文を用いてCircleオブジェクトを定義してインスタンス化した1例が次のコード。

<canvas id="cd_circle" width="300" height="120"></canvas>
<script>
// クラスを定義
class Circle{
   // 各種プロパティを宣言
   #radius; // 円の半径
   #line_width; // 線の太さ
   #stroke_color; // 線の色
   #fill_color; // 塗りつぶす色
      
   // コンストラクター(初期値を代入する函数)
   constructor(strokeColor,fillColor){
      this.#radius = 30;
      this.#line_width = 5;
      this.#stroke_color = strokeColor || 'blue';
      this.#fill_color = fillColor || 'skyblue';
   }

   // 各プロパティの値を取得するメソッド
   getRadius(){return this.#radius;}
   getLineWidth(){return this.#line_width;}
   getStrokeColor(){return this.#stroke_color;}
   getFillColor(){return this.#fill_color;}

   // 各プロパティの値を設定するメソッド
   setRadius(arg){this.#radius = arg;}
   setLineWidth(arg){this.#line_width = arg;}
   setStrokeColor(arg){this.#stroke_color = arg;}
   setFillColor(arg){this.#fill_color = arg;}

   // 円を描くメソッド(canvas要素のID、水平座標、垂直座標)
   draw(canvasId,x,y){
      // HTML5 Canvasの2DコンテキストのAPIを使う
      const canvas = document.getElementById(canvasId);
      const ctx = canvas.getContext('2d');
      ctx.beginPath(); // パスの初期化
      // 円のパス(水平座標、垂直座標、半径、始点、終点)
      ctx.arc(x,y,this.#radius,0,Math.PI*2);
      ctx.lineWidth = this.#line_width; // 線の太さ
      ctx.strokeStyle = this.#stroke_color; // 線の色
      ctx.stroke(); // 円を描く
      ctx.fillStyle = this.#fill_color; // 塗りつぶす色
      ctx.fill(); // 塗りつぶす
   }
}

// Circleクラスから個々の円オブジェクトを作成
const circle1 = new Circle();
const circle2 = new Circle('orange','yellow');
const circle3 = new Circle('red','pink');

// 円を描くメソッドを呼び出す
circle1.draw('cd_circle',60,60);
circle2.draw('cd_circle',130,60);
circle3.draw('cd_circle',200,60);

// 円の線の太さを再設定
circle1.setLineWidth(8);
circle2.setLineWidth(8);
circle3.setLineWidth(8);

// 少し下の座標に円を描く
circle1.draw('cd_circle',60,130);
circle2.draw('cd_circle',130,130);
circle3.draw('cd_circle',200,130);
</script>

クラス構文はC++やJavaのクラス宣言に近い。コンストラクターと呼ばれるメンバ函数はC++やJavaではクラス名と同じ名前を使う決まりがあるが、JavaScriptのクラス構文ではconstructorキーワードを用いる。

このコードをHTMLドキュメントのbody要素の間に埋め込んでウェブ・ブラウザで読み込むと色や線の太さが異なる6つの円が次のように描かれるはず。

このウェブブラウザはHTML5 CanvasかJavaScriptに対応していません。

getキーワードとsetキーワード

ECMAScript 2015(ES6)からgetとsetというキーワードを用いてゲッターとセッターを記述できるようになっている。例えば次のような書式によって。

get ゲッター名(){
   return this.#プロパティ名;
}

set セッター名(仮引数){
   this.#プロパティ名 = 仮引数;
}

getとsetを用いた際に気をつけるべき点としてこの構文がメソッドの定義ではないということ。したがってgetやsetを使って定義されたゲッターとセッターをメソッドのように呼び出すとエラーが生じてしまう。

getとsetを用いて定義されたゲッターとセッターは通常のデータ・プロパティのようにアクセスする必要がある。

const 変数名 = オブジェクト名.ゲッター名; // 取得する
オブジェクト名.セッター名 = 値; // 設定する

コメント

このブログの人気の投稿

Visual Studio 2019にはC++のためのフォームデザイナーがない件

10の補数と9の補数と2の補数と1の補数

LATEXで数式:指数と順列などで使う添数・添字