【JavaScriptクイズ】第4問:いつでも最新の値を取得できるプロパティの作り方

2023/04/01に公開

JavaScriptの文法や便利な使い方について、気軽なクイズ形式で解説する記事を書いていきます。

今回のテーマは「プロパティの取得」です。では、さっそく問題です!

問題

三角形を扱うJavaScriptのプログラムを作りました。「底辺の長さ」と「高さ」から、「面積」を計算するというものです。

quiz.js
"use strict";

class Triangle {
  constructor(base, height) {
    this.base = base;
    this.height = height;
    
    this.updateArea();
  }

  updateArea() {
    this.area = this.base * this.height / 2.0;
  }
}

// 「底辺の長さ」が6、「高さ」が4の三角形の「面積」は?
let t = new Triangle(6, 4);
console.log(`三角形の面積は${t.area}です。`);

// 「底辺の長さ」を7にすると、「面積」はいくつになる?
t.base = 7;
t.updateArea();
console.log(`三角形の面積は${t.area}になりました。`);

実行結果
三角形の面積は12です。
三角形の面積は14になりました。

クラスTriangleには、3つのプロパティがあります。

  • base:底辺の長さ
  • height:高さ
  • area:面積

areaは、関数updateAreaを実行するとbaseheightから計算されます。そのため、プログラム中には次のような行があるのですが……

t.updateArea();

この1行を書かないと、areaを最新の値に更新できないところが不満です。いつでも最新のareaの値を取得できるようにするには、どうすればいいか分かりますか?

ヒントを見る?

areaの値が、常にbaseheightから計算されるようにするには?

答えを見る?

「ゲッター(getter)」を使えば、プログラムは次のように書けます。

quiz.js
"use strict";

class Triangle {
  constructor(base, height) {
    this.base = base;
    this.height = height;
  }

  get area() {
    return this.base * this.height / 2.0;
  }
}

// 「底辺の長さ」が6、「高さ」が4の三角形の「面積」は?
let t = new Triangle(6, 4);
console.log(`三角形の面積は${t.area}です。`);

// 「底辺の長さ」を7にすると、「面積」はいくつになる?
t.base = 7;
console.log(`三角形の面積は${t.area}になりました。`);

解説

問題のプログラムでは、「面積」の計算結果をいったんareaに格納して覚えておき、あとで取得できるようにしていました。

class Triangle {
  constructor(base, height) {
    this.base = base;
    this.height = height;
    
    this.updateArea();
  }

  updateArea() {
    this.area = this.base * this.height / 2.0; // 計算結果をareaに格納
  }
}

いつでも最新の「面積」を得られるようにするには、値を取得するときに計算するのがいいでしょう。順を追って、やり方を説明します。

ステップ1:最新の値を関数で取得する

まずは、「面積」を計算して返す関数を作りましょう。具体的には、次のようにします。

class Triangle {
  constructor(base, height) {
    this.base = base;
    this.height = height;
  }

  getArea() { // 関数なら、いつでも最新の計算結果を返せる
    return this.base * this.height / 2.0;
  }
}

updateAreaを廃止して、代わりにgetAreaを作りました。この関数は、計算結果を覚えておくのではなく、その場で返すという動作をします。

これにより、プログラムの後半は次のように変わります。

// 「底辺の長さ」が6、「高さ」が4の三角形の「面積」は?
let t = new Triangle(6, 4);
console.log(`三角形の面積は${t.getArea()}です。`);

// 「底辺の長さ」を7にすると、「面積」はいくつになる?
t.base = 7;
console.log(`三角形の面積は${t.getArea()}になりました。`);

目論見どおり、updateAreaを呼び出していた1行をなくすことができました。

でも、t.areaとプロパティを取得するだけで済んでいた部分を、t.getArea()と関数呼び出しに置き換える必要がありました。これは、やりたかったこととは違うので、もう一工夫必要です。

ステップ2:値をプロパティとして取得する

JavaScriptには、プロパティを関数に結び付ける「ゲッター」という仕組みがあります。これを使えば、関数の戻り値をプロパティとして取得することが可能です。

具体的には、getというキーワードを使って、次のように書きます。

class Triangle {
  constructor(base, height) {
    this.base = base;
    this.height = height;
  }

  get area() { // この関数の戻り値はプロパティのように取得できる
    return this.base * this.height / 2.0;
  }
}

これにより、プログラムの後半部分は次のようになります。

// 「底辺の長さ」が6、「高さ」が4の三角形の「面積」は?
let t = new Triangle(6, 4);
console.log(`三角形の面積は${t.area}です。`);

// 「底辺の長さ」を7にすると、「面積」はいくつになる?
t.base = 7;
console.log(`三角形の面積は${t.area}になりました。`);

以上で、プロパティt.areaによる「面積」の取得方法を変更することなく、updateAreaの呼び出しを削除できました!

まとめ

JavaScriptでは、「ゲッター(getter)」を使うとプロパティの取得を関数に結び付けられます。もしかすると、「ゲッターがあるのなら、セッターもあるのでは?」と思った人もいるかもしれませんね。そのとおりです!プロパティへの書き込みも、「セッター(setter)」を使って関数に結び付けることが可能です。

とはいえゲッターとセッターは、あまり使いすぎるとプログラムが複雑になってしまうかもしれません。メリットを感じられるときにだけ使うのがおすすめです。

「ほかのプロパティによって値が決まるプロパティ」を作りたいときは、ゲッターを使うメリットがあるでしょう。今回のプログラムは、

  • 「底辺の長さ」と「高さ」によって、「面積」が決まる

というものでした。ほかには……

  • 「速さ」と「時間」によって、「距離」が決まる
  • 「赤(Red)」と「緑(Green)」と「青(Blue)」によって、「カラーコード(RGB値)」が決まる

などの場合にも、うまく活用すればプログラムをスッキリ書けるのではないかと思います。

なお、下記のページには、今回とよく似た「三角形の面積」を題材にしたC言語のクイズがあります。よろしければ、チェックしてみてください。

https://curiocube.team-aries.com/cquiz-q14/

また、下記の本では「素数の探索」を題材に、JavaScriptとC言語を含む10種類のプログラミング言語を紹介しています。

https://zenn.dev/teamariesdotcom/books/af56bae422969b

Discussion