Chapter 02

データプロパティとゲッター

OJK
OJK
2021.09.27に更新

今回は petite-vue の「変数」にあたる データプロパティと口ひげ構文 {{ }} についてもう少し掘り下げていきます。また、データプロパティの一種として利用できる JavaScript のゲッター(get 構文)も紹介します。

雛形コード
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>petite-vue入門</title>
</head>
<body>

  <p>Hello {{message}}</p>

  <script src="https://unpkg.com/petite-vue"></script>
  <script src="script.js"></script>
</body>
</html>
script.js
'use strict';

PetiteVue.createApp({
  message: 'World!!'
}).mount();

口ひげ構文とデータプロパティ

まずは軽く復習しましょう。冒頭のサンプルコードの中身です。

HTML
<p>Hello {{message}}</p>
JS
PetiteVue.createApp({
  message: 'World!!'
}).mount();

createApp メソッドの引数(オブジェクト)の中で定義されたプロパティは、口ひげ構文を介して、HTML の開始タグと終了タグの間で使えるのでした。上記の例では message がそのプロパティです。Vue ではこのプロパティを「データプロパティ」と呼びます。

この口ひげ構文の仕組みによって HTML の中に「JavaScript の変数」を持ち込むことができます。JavaScript 側でデータプロパティに変更を加えると、対応する HTML 側の口ひげ構文の値も即座に変更されます。これをデータバインディングというのでした。

口ひげ構文の中に書けるのはデータプロパティ単体だけではありません。JavaScript の “式” が書けます。“式” というのは「代入や制御構文を含まない 1 行のコード」と覚えておけばひとまずは OK です。

さて、上記のサンプルコードは文字列の加算を使って次のようにも書けます。

HTML
<p>{{'Hello' + message}}</p>

複数のデータプロパティを口ひげ構文内の式に含めることもできますし、データプロパティがオブジェクトであればそのメソッドも呼び出せます(JavaScript では配列もオブジェクトです)。

HTML
<p>{{idx}}番目の値は“{{array[idx]}}”です</p>
<p>配列の中身: {{array.join('と')}}</p>
JS
PetiteVue.createApp({
  array: ['a', 'b', 'c'],
  idx: 2
}).mount();

結果

また同様に、データプロパティの値も JavaScript の式です。したがって、簡単な計算なら以下のようにデータプロパティの定義でやってしまっても構いません。

HTML
<p>{{message}}</p>
<p>{{array}}</p>
JS
PetiteVue.createApp({
  message: 'Hello' + ' ' + 'World!!',
  array: ['a', 'b', 'c'].join('と')
}).mount();

式で表現できる諸々

JavaScript の式で表現できることをいろいろと知っていると便利なことがあります。JavaScript の復習がてら、いくつか押さえておきましょう。

三項演算子

三項演算子は if-else 文を短く表現する方法です。条件式は、条件が満たされたときには true、満たされなかったときには false というブール値(Boolean 型)になります。

三項演算子
条件式 ? trueだったときの式 : falseだったときの式

例を示します。

HTML
<p>回答は {{flag ? answer[0] : answer[1]}} です</p>
<!-- 「回答は Yes です」になる -->
JS
PetiteVue.createApp({
  flag: true,
  answer: ['Yes', 'No']
}).mount();

データプロパティ flag が true なので、三項演算子の結果として answer[0] が選ばれます。ここでは選択肢に配列を使っていますが、どんな式を指定しても構いません(普通の変数や単なる文字列や数値など)。

三項演算子の詳細は こちら を参照してください。

Null 合体演算子

Null 合体演算子(??)は論理演算子のひとつで、null と undefined を除外するための条件分岐で使えます。

Null合体演算子
A ??B
// 式Bは、式Aがnullもしくはundefinedのときに選ばれる

例を示します。

HTML
<p>{{data ?? 'データがありません'}}</p>
JS
PetiteVue.createApp({
  data: localStorage.notExistKey
}).mount();

ローカルストレージから「notExistKey」というキー名のデータを取得しようとしていますが、(キー名のとおり)存在しないキーなので data の値は undefined になってしまいます。Null 合体演算子によって口ひげ構文に undefined が入ってしまうことを防いでいます。

大抵のウェブアプリケーションでは、どこかからデータを取得して HTML で表示するという処理があります。何らかの原因でデータが取得できないときには、null もしくは undefined という値が返ってきます。null や undefind がプログラムに入り込むとエラーになったり予想外の結果になったりするので、Null 合体演算子で代替値を用意する癖をつけておきましょう。

似たような構文に OR 演算子(||)を使った記法がありますが、OR 演算子は数値の 0 や 空の文字列/配列も false とみなして弾いてしまうので思わぬバグに繋がります。Null 合体演算子は比較的新しい機能なので、ネット上に転がっているコードには OR 演算子を使ったものもよく見られます。そのままコピペしてよいかどうか適宜判断しましょう。

ラムダ式メソッド

JavaScript の配列には一般に “ラムダ式” と呼ばれる形式のメソッドが用意されています。配列への繰り返し処理を(文ではなく)式で記述することができます。ここでは find メソッドを紹介しますが、他にも便利なラムダ式メソッドがたくさんあります。

find メソッドは、配列の要素を順番に条件式にかけていき、最初に条件を満たした要素を返します。メソッドが値を「返す」というのは、「メソッドがその値に置き換わる」ということです。

findメソッド
配列.find(要素 => 条件式)

例を示します。

HTML
<p>数値:{{data.find(el => el > 3)}}</p>
<!-- 「数値:4」と表示される -->
JS
PetiteVue.createApp({
  data: [1, 2, 3, 4, 5]
}).mount();

el という変数に配列 data の要素がひとつずつ代入されて、el > 3 という条件式に順番にかけられます。要素の値が 4 になったところで条件を満たすので、data.find(el => el > 3) という式が 4 に置き換わります。

ラムダ式メソッドの詳細は こちら を参照してください。

ゲッター

口ひげ構文の中で使える便利な式を紹介してきましたが、口ひげ構文の中に代入や制御構文を含む “文” を記述することはできません。また、式で書けたとしても、同じ表現が二箇所以上に出てくる場合は一箇所にまとめたほうがよいです。

その場合には、JavaScript の “ゲッター/getter” という仕組みが使えます。後述するように、定義方法はメソッドのようなのですが、値を参照するときには変数として振る舞うので、データプロパティの一種という扱いになります。petite-vue では意外と使いますのでしっかり理解してください。

具体例から見てみましょう。

JS
PetiteVue.createApp({
  // ゲッターの定義
  get fullName() {
    const lastName = 'OJK';
    const firstName = 'Alexander';

    return firstName + ' ' + lastName;
  }
}).mount();

ゲッターの定義は、戻り値ありのメソッド定義とほぼ同じですが、ゲッター名の前に get というキーワードを付けます。

HTML 側では、口ひげ構文にゲッター名を記述すると、ゲッターの戻り値(return に指定した値もしくは式)に置き換わります。ゲッター名の末尾に丸括弧 () を付けないことに注意してください。あくまで「変数/プロパティ」として参照します。

HTML
<p>{{fullName}}</p>
<!-- 「Alexander OJK」と表示される -->

ゲッターの構文は次のとおりです。

get構文(定義)
get ゲッター名() {
  /* 前処理(必要ならば) */
  return 値/式;
}
get構文(使用時)
<p>{{ゲッター名}}</p>

通常のメソッド定義とは違い、ゲッターは引数が受け取れません。呼び出し時に丸括弧が付けられないので当然ですね。そして、定義では必ず return が必要です。

なお、ゲッターには「あとから代入で値を変更できない」という問題(というか特性)があります。代入によって値を変更するには、セッター/setter を定義する必要があります。セッターについては チャプター 8 で取り上げます。

Vue を使う

本家 Vue ではゲッターは基本的に使いません。ここが petite-vue との大きな違いのひとつです。Vue にはゲッターの代わりに使える算出プロパティがあります。createApp メソッドの引数内に computed というプロパティを用意し、その値をオブジェクトとします。そのオブジェクトの中で定義されたメソッドは、ゲッターと同じようにデータプロパティの扱いとなります。

JS
Vue.createApp({
  computed: {
    fullName() {  // キーワード get は不要
      const lastName = 'OJK'
      const firstName = 'Alexander'

      return firstName + ' ' + lastName;
    }
  }
}).mount('body');
HTML
<p>{{fullName}}</p>
<!-- 末尾の () は付けない -->

this キーワード

さきほどのゲッターの例ではデータプロパティを使っていませんでしたが、これを次のように変更するとどうなるでしょうか。lastName と firstName をゲッターの定義の外に出して、データプロパティに変更しました。

JS
PetiteVue.createApp({
  lastName: 'OJK',        // ←
  firstName: 'Alexander', // ←
  get fullName() {
    return firstName + ' ' + lastName;
  }
}).mount();
HTML
<p>{{fullName}}</p>

おそらく何も表示されず、ブラウザのコンソールを確認すると「firstName is not defined」といったようなエラーメッセージが表示されているかと思います。firstName という変数は定義されていない…と言われています。

これは素の JavaScript のメソッド定義と同じなのですが、同じオブジェクトのプロパティやメソッドを呼び出すときは、this. を頭に付ける必要があります。ここでの this は「このオブジェクト」を指しており、this.firstNameは「このオブジェクトの firstName」を意味します。

JS
PetiteVue.createApp({
  lastName: 'OJK',
  firstName: 'Alexander',
  get fullName() {
    return this.firstName + ' ' + this.lastName; // ←
  }
}).mount();

オブジェクトの外に出てしまえば this を使う必要はありませんので、口ひげ構文では this は登場しません。逆に this を付けてしまうと何も表示されなくなります。

HTML
<!-- 何も表示されない -->
<p>{{this.firstName}}</p>

<!-- 正しくはこう -->
<p>{{firstName}}</p>
Vue を使う

本家 Vue も同じです。データプロパティの定義に合わせて復習しておきましょう。

JS
Vue.createApp({
  data() {
    return {
      lastName: 'OJK',
      firstName: 'Alexander'
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName;
    }
  }
}).mount('body');