基礎から学ぶJavaScript入門 90日コース | 実践的なJavaScript - Day 73:再利用可能な関数

JavaScript 90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク

Day 73:再利用可能な関数

Day 73では、何度も使える処理を小さな関数としてまとめる方法を学びます。今回のテーマは、Utility関数と共通処理です。実践では、日付フォーマット、文字列処理、数値フォーマットを例に、入力を受け取り、整えた結果を返す関数を作ります。

Day 72では、API処理・データ処理・UI処理を役割ごとに分けました。Day 73では、そのうち複数の場面から使える処理を取り出し、再利用しやすい形にします。たとえば、日付を画面に表示する場所が複数あれば、毎回同じ書式変換を書くのではなく、共通の関数を使えます。こうすると、同じ処理を何度も書く手間が減り、表示ルールを変えるときも修正箇所をまとめられます。

Utility関数とは

Utility関数とは、日付や文字列、数値などに対する、汎用的で小さな処理をまとめた関数です。アプリの特定画面だけに依存せず、複数の場所から呼び出せるように作ります。

たとえば、次のような関数がUtility関数に向いています。

  • 日付を「2026年11月4日」のような形に整える
  • 文字列の前後の空白を取り除く
  • 数値を桁区切りで表示する
  • 金額に通貨記号を付けて表示する

関数にする基本形は、「入力を受け取り、決まった処理を行い、結果を返す」です。画面の要素を直接変更するのではなく、値を返すようにすると、画面表示やテストから独立して使いやすくなります。

なぜ共通処理を関数にするのか

同じ処理を複数の場所にコピーすると、あとからルールを変えたときに、すべてのコピーを探して直さなければなりません。修正漏れがあると、画面によって書式が異なることもあります。

一方、共通処理を関数にまとめれば、呼び出す場所は同じ関数を使うだけです。たとえば日付の表示ルールを変更するときは、その関数を直せば、利用している場所へ同じルールを適用できます。

ただし、似ている処理を何でも無理に共通化する必要はありません。役割やルールが本当に同じ処理をまとめることが大切です。

最初に決めること:関数の約束

関数を作る前に、入力と出力の約束を決めます。たとえば、日付フォーマット関数なら、「どの形式の値を受け取るか」「不正な値ならどうするか」「何を返すか」を決めます。

  • 入力:JavaScriptの`Date`オブジェクト、または日付として解釈できる値
  • 出力:指定した表示形式の日付文字列
  • 不正な入力:エラーを投げる、または決めた代替表示を返す

この約束が曖昧なままだと、呼び出す側が関数の扱いに迷います。初心者の方は、関数を作るときに「何を受け取り、何を返すか」を先に言葉で説明する習慣をつけるとよいです。

ステップ1:文字列を整えるUtility関数

まず、文字列の前後にある空白を取り除く関数を作ります。検索欄やフォーム入力の処理でよく使う共通処理です。

// 文字列の前後の空白を取り除いて返す
export function trimText(value) {
  // 文字列以外を誤って受け取った場合は、扱い方を明確にする
  if (typeof value !== "string") {
    throw new TypeError("trimTextには文字列を渡してください。");
  }

  return value.trim();
}
JavaScript

使うときは次のようにします。

import { trimText } from "./utils.js";

const keyword = trimText("  JavaScript  ");

console.log(keyword); // "JavaScript"
JavaScript

ここでは、trim()を呼び出すだけの小さな関数にしています。アプリ内で同じ入力ルールを使いたいとき、関数名で意図を示せるのが利点です。ただし、単に一度だけ使う短い処理なら、関数にする必要はありません。複数の場所で使う、またはルールに名前を付けたい場合に関数化を検討します。

文字列の表記ゆれも整える

検索で大文字・小文字を区別したくないときは、文字列を同じ形にそろえてから比較できます。

// 検索用に文字列の前後の空白を取り、大文字小文字をそろえる
export function normalizeSearchText(value) {
  if (typeof value !== "string") {
    throw new TypeError("normalizeSearchTextには文字列を渡してください。");
  }

  return value.trim().toLowerCase();
}
JavaScript

たとえば、検索語がJavaScriptでもjavascriptでも、小文字にそろえることで比較しやすくなります。

import { normalizeSearchText } from "./utils.js";

const keyword = normalizeSearchText(" JavaScript ");
const title = normalizeSearchText("JavaScript 入門");

// 両方を同じルールで整えてから検索する
console.log(title.includes(keyword)); // true
JavaScript

文字列をどこまで整えるかは、アプリの目的によって異なります。日本語検索などでは、英字の大文字・小文字だけをそろえれば十分な場合もあります。入力を必要以上に変換すると、本来区別したい文字まで変わることがあるため、目的に合わせてルールを決めましょう。

ステップ2:日付をフォーマットする

JavaScriptのDateオブジェクトは日付や時刻を扱えますが、そのまま表示すると読みづらい場合があります。Intl.DateTimeFormatを使うと、指定した地域やタイムゾーンに合わせた表示を作れます。

// 日付を日本語の年月日形式に整えて返す
export function formatDate(value) {
  const date = value instanceof Date ? value : new Date(value);

  // 無効な日付かどうかを確認する
  if (Number.isNaN(date.getTime())) {
    throw new TypeError("有効な日付を指定してください。");
  }

  // 日本語・日本時間の年月日として表示する
  return new Intl.DateTimeFormat("ja-JP", {
    year: "numeric",
    month: "long",
    day: "numeric",
    timeZone: "Asia/Tokyo"
  }).format(date);
}
JavaScript

使い方は次の通りです。

import { formatDate } from "./utils.js";

const publishedAt = new Date("2026-11-04T09:30:00+09:00");

console.log(formatDate(publishedAt));
// 例: 2026年11月4日
JavaScript

日付で注意したいのは、日付と時刻のタイムゾーンです。APIから届く日時がUTCなのか、日本時間なのかを確認しないまま表示すると、環境によって時刻や日付がずれて見える場合があります。日時を扱うときは、入力データの形式と表示したいタイムゾーンを決めておきましょう。

ステップ3:数値を読みやすく表示する

大きな数値は、桁区切りを入れると読みやすくなります。Intl.NumberFormatを使うと、地域に合わせた数値表示を作れます。

// 数値を日本語形式の桁区切りで表示する
export function formatNumber(value) {
  // 数値以外やNaN、Infinityを誤って表示しないよう確認する
  if (typeof value !== "number" || !Number.isFinite(value)) {
    throw new TypeError("formatNumberには有限の数値を渡してください。");
  }

  return new Intl.NumberFormat("ja-JP").format(value);
}
JavaScript
import { formatNumber } from "./utils.js";

console.log(formatNumber(1234567)); // "1,234,567"
JavaScript

金額を表示する場合は、通貨形式を指定できます。

// 数値を日本円の通貨形式で表示する
export function formatYen(value) {
  if (typeof value !== "number" || !Number.isFinite(value)) {
    throw new TypeError("formatYenには有限の数値を渡してください。");
  }

  return new Intl.NumberFormat("ja-JP", {
    style: "currency",
    currency: "JPY"
  }).format(value);
}
JavaScript
import { formatYen } from "./utils.js";

console.log(formatYen(2500)); // 例: ¥2,500
JavaScript

Intl.NumberFormatを使うと、桁区切りや通貨記号の表示を自分で組み立てずに済みます。数値を文字列へ変換してから処理するのではなく、数値のまま渡すのが基本です。

ステップ4:Utility関数をファイルにまとめる

Day 71で学んだES Modulesを使い、共通関数をutils.jsへまとめます。たとえば、次のような構成にできます。

project/
├── index.html
└── js/
    ├── app.js
    └── utils.js

js/utils.jsには、今回作った関数をまとめます。

// 文字列の前後の空白を取り除く
export function trimText(value) {
  if (typeof value !== "string") {
    throw new TypeError("trimTextには文字列を渡してください。");
  }

  return value.trim();
}

// 検索用に文字列を整える
export function normalizeSearchText(value) {
  if (typeof value !== "string") {
    throw new TypeError("normalizeSearchTextには文字列を渡してください。");
  }

  return value.trim().toLowerCase();
}

// 日付を日本語の年月日形式に整える
export function formatDate(value) {
  const date = value instanceof Date ? value : new Date(value);

  if (Number.isNaN(date.getTime())) {
    throw new TypeError("有効な日付を指定してください。");
  }

  return new Intl.DateTimeFormat("ja-JP", {
    year: "numeric",
    month: "long",
    day: "numeric",
    timeZone: "Asia/Tokyo"
  }).format(date);
}

// 数値を桁区切りで表示する
export function formatNumber(value) {
  if (typeof value !== "number" || !Number.isFinite(value)) {
    throw new TypeError("formatNumberには有限の数値を渡してください。");
  }

  return new Intl.NumberFormat("ja-JP").format(value);
}

// 数値を日本円として表示する
export function formatYen(value) {
  if (typeof value !== "number" || !Number.isFinite(value)) {
    throw new TypeError("formatYenには有限の数値を渡してください。");
  }

  return new Intl.NumberFormat("ja-JP", {
    style: "currency",
    currency: "JPY"
  }).format(value);
}
JavaScript

ステップ5:別のファイルから利用する

app.jsから必要な関数を読み込みます。使う関数だけをimportすると、何に依存しているかがわかりやすくなります。

// utils.jsから必要な関数を読み込む
import {
  formatDate,
  formatNumber,
  formatYen,
  normalizeSearchText,
  trimText
} from "./utils.js";

// 入力文字列を整える
const keyword = trimText("  JavaScript  ");

// 検索用の文字列に変換する
const normalizedKeyword = normalizeSearchText(keyword);

// 日付・数値・金額を整形する
const dateText = formatDate("2026-11-04T09:30:00+09:00");
const countText = formatNumber(1234567);
const priceText = formatYen(2500);

// 整形した値を確認する
console.log(normalizedKeyword);
console.log(dateText);
console.log(countText);
console.log(priceText);
JavaScript

ブラウザーで使う場合は、HTMLからapp.jsをモジュールとして読み込みます。

<!-- ES Modulesとしてapp.jsを読み込む -->
<script type="module" src="./js/app.js"></script>

再利用可能な関数にするためのポイント

関数を再利用しやすくするには、いくつかの基本があります。

  • 関数名から処理の内容が想像できるようにします。
  • 入力と戻り値を明確にします。
  • できるだけ一つの目的に絞ります。
  • 引数で必要な値を受け取り、外部の変数に過度に依存しないようにします。
  • 不正な入力を受け取った場合の動きを決めます。

特に、関数の中でHTML要素を直接探したり、画面の状態を変更したりしないUtility関数は、別の画面や別のアプリでも使いやすくなります。たとえば、formatDate(date)が文字列を返す形なら、カード表示でもテーブル表示でも同じ関数を利用できます。

テストしやすい関数にする

入力を受け取って結果を返す関数は、画面を開かなくても動作を確認しやすいです。まずはコンソールで、通常の値と境界となる値を試してみます。

import { formatNumber, formatYen, normalizeSearchText } from "./utils.js";

// 通常の値を確認する
console.log(formatNumber(1500));
console.log(formatYen(1500));
console.log(normalizeSearchText("  Hello  "));

// 不正な入力ではエラーになることを確認する
try {
  formatNumber("1500");
} catch (error) {
  console.error(error.message);
}
JavaScript

この例のformatNumber()は数値だけを受け付け、文字列の"1500"は受け付けません。どの入力を許可するかは設計によって異なりますが、関数のルールを決めて一貫させることが大切です。

初心者が注意したい設計上のポイント

Utility関数は便利ですが、何でもutils.jsに詰め込むと、ファイルが大きくなって探しにくくなります。関数が増えてきたら、役割ごとにファイルを分ける方法もあります。

  • `dateUtils.js`:日付に関する処理
  • `stringUtils.js`:文字列に関する処理
  • `numberUtils.js`:数値に関する処理

小さな学習アプリでは、まず一つのutils.jsで構いません。必要以上に細かく分けず、探しやすさや再利用のしやすさを見ながら整理します。

また、関数が「何でもする」状態にならないように注意します。たとえば「日付を整形し、DOMを書き換え、API通信もする関数」は、複数の役割が混ざっています。Day 72で学んだ役割分担を思い出し、Utility関数は値の変換や共通処理に集中させましょう。

情報セキュリティの観点

文字列を画面へ表示するときは、APIやユーザー入力の値をそのままHTMLとして解釈させないことが大切です。表示にはtextContentを使うのが基本です。Utility関数で文字列を整えたとしても、それだけで安全なHTMLになるわけではありません。文字列の整形と、画面への安全な表示は別の処理として考えます。

また、日付や数値の関数で不正な入力をどう扱うかを明確にしておくと、予期しない値による表示崩れを防ぎやすくなります。

Day 73の練習課題

基本の関数を動かしたら、次の課題に取り組んでみましょう。

  • `formatDate()`に曜日を表示する設定を追加します。
  • 文字列の連続した空白を1つにまとめる関数を作ります。
  • 小数を指定した桁数に丸めて表示する関数を作ります。
  • 日付や数値の不正な入力を渡し、エラーの動きを確認します。
  • 作ったUtility関数を、別の画面表示処理から読み込んで使います。

追加機能を作るときは、まず「入力は何か」「返す値は何か」「失敗時はどうするか」を決めてからコードにしましょう。

Day 73のゴール

Day 73では、次のことができるようになっていれば十分です。

  • Utility関数が共通処理をまとめるものだと説明できる
  • 入力を受け取り、結果を返す関数を作れる
  • 日付・文字列・数値の整形処理を関数化できる
  • ES Modulesの`export`と`import`で関数を再利用できる
  • 入力値や不正な値の扱いを関数ごとに決められる

まとめ

Day 73では、Utility関数と共通処理を学び、日付フォーマット、文字列処理、数値フォーマットを再利用可能な関数として作りました。大切なのは、同じ処理を何度もコピーするのではなく、入力と出力が明確な関数にまとめることです。さらに、ES Modulesを使って関数を別ファイルへ置けば、必要な場所から読み込んで利用できます。

ただし、関数化そのものが目的ではありません。何度も使う処理や、名前を付けてルールを統一したい処理を、無理のない単位でまとめることが重要です。今回の関数を実際に使い、入力と戻り値、不正な入力への対応を確認しながら、読みやすく再利用しやすいコードを書く習慣を身につけていきましょう。

タイトルとURLをコピーしました