関数呼び出し埋め込みとは何か
テンプレート文字列はバッククォートで囲み、${ ... } の中に“任意の式”を置けます。その式に関数呼び出しを書けば、戻り値が文字列の中にそのまま埋め込まれます。ここが重要です:変数だけでなく、計算・整形・サニタイズなどを関数で表現し、テンプレートには“見た目”だけを残すと読みやすく保守しやすいコードになります。
const name = "Alice";
const upper = s => s.toUpperCase();
const msg = `Hello, ${upper(name)}!`;
console.log(msg); // Hello, ALICE!
JavaScript基本構文と文字列化のルール
任意の関数を呼び出して結果を挿入できる
${ ... } の中では通常の JavaScript と同じく、関数呼び出し・メソッドチェーン・三項演算子などが使えます。戻り値は自動的に文字列化されて結合されます。
const price = 123456;
const fmt = n => n.toLocaleString("ja-JP");
const text = `合計: ${fmt(price)} 円`;
JavaScriptオブジェクトはそのままでは [object Object]
関数がオブジェクトを返す場合、暗黙に文字列化されると [object Object] になります。ここが重要です:必要に応じて JSON 化や独自フォーマットで“文字列”にしてから埋め込みます。
const getUser = () => ({ id: 7, name: "Alice" });
const s1 = `user=${getUser()}`; // user=[object Object]
const s2 = `user=${JSON.stringify(getUser())}`; // user={"id":7,"name":"Alice"}
JavaScript整形を関数に分離する(見た目とロジックの分離)
テンプレート内に複雑な処理を書きすぎると読みにくくなります。ここが重要です:整形や計算は“補助関数”へ切り出し、テンプレートは最小限の埋め込みにするのが定石です。
const pad2 = n => String(n).padStart(2, "0");
const formatTime = d => `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`;
const sanitizeHtml = s => String(s).replace(/[&<>"']/g, c => ({
"&": "&", "<": "<", ">": ">", '"': """, "'": "'"
}[c]));
const now = new Date();
const userInput = `<Alice>`;
const html = `
<div class="card">
<h1>現在時刻: ${formatTime(now)}</h1>
<p>こんにちは、${sanitizeHtml(userInput)} さん。</p>
</div>
`;
JavaScript非同期関数の結果を埋め込む(async/await と組み合わせ)
テンプレート内でも await は“式”なので使えます。ただし、await は async 関数(またはトップレベル await が許される環境)内でのみ有効です。ここが重要です:非同期処理の結果を埋め込むときは、テンプレートを組み立てる関数自体を async にします。
// async 関数内ならテンプレート内で await が使える
const fetchJson = async url => (await fetch(url)).json();
async function page() {
const data = await fetchJson("/api/item/1");
return `
<h1>${data.title}</h1>
<p>価格: ${(data.price).toLocaleString("ja-JP")} 円</p>
`;
}
JavaScriptパフォーマンスと副作用(重要ポイントの深掘り)
関数呼び出しは毎回評価されます。ここが重要です:重い処理や副作用(ログ、DOM 操作など)を ${ ... } の中で直接行うのは避け、事前計算した値を埋め込むほうが安全で速いです。ループ内でテンプレートを量産する場合は、共有の整形関数や定数を外に出して再利用します。
// 悪い例:テンプレート内で重い処理を直接
const bad = name => `結果: ${slowCompute(name)}`;
// 良い例:外で事前に計算してから埋め込む
const good = name => {
const result = slowCompute(name);
return `結果: ${result}`;
};
JavaScriptまた、例外を投げる関数をテンプレート内で呼ぶと、その場でテンプレートの評価が失敗します。必要なら try/catch で値を用意してから埋め込みます。
const safeLine = user => {
let label;
try {
label = makeLabel(user); // 例外が出る可能性あり
} catch {
label = "(不明)";
}
return `ユーザー: ${label}`;
};
JavaScript実用例で理解を固める
// 1) テーブル行を生成:整形関数を活用
const yen = n => `${n.toLocaleString("ja-JP")} 円`;
const rowHtml = ({ id, price, active }) => `
<tr class="${active ? "on" : "off"}">
<td>${id}</td>
<td>${yen(price)}</td>
</tr>
`;
console.log(rowHtml({ id: 1, price: 123456, active: true }));
// 2) クエリ付き URL:エンコード関数を埋め込み
const q = "JS 入門 & 実践";
const url = base => `${base}?q=${encodeURIComponent(q)}&page=${1}`;
console.log(url("/search"));
// 3) メール本文:条件と関数呼び出しの併用
const upper = s => s.toUpperCase();
const planBadge = p => (p === "Pro" ? "★PRO" : "FREE");
const mail = ({ name, plan, note }) => `
こんにちは、${upper(name)} さん
ご利用中のプラン: ${planBadge(plan)}
${note ? `追記: ${note}\n` : ""}
よろしくお願いいたします。
`;
console.log(mail({ name: "Alice", plan: "Pro", note: "" }));
// 4) 非同期データでページ断片を組み立て
const fetchJson = async url => (await fetch(url)).json();
async function section() {
const user = await fetchJson("/api/user/7");
const money = (user.balance).toLocaleString("ja-JP");
return `
<section>
<h2>${user.name}</h2>
<p>残高: ${money} 円</p>
</section>
`;
}
JavaScriptまとめ
関数呼び出し埋め込みの核心は「${ ... } に関数を呼んで、戻り値を直接テンプレートへ挿入する」ことです。オブジェクトはそのままだと [object Object] になるため文字列化する、複雑な整形は補助関数へ分離する、重い処理は事前計算する、非同期はテンプレートを組み立てる関数ごと async にする。この指針を守れば、初心者でも見た目とロジックを美しく分離しながら、実用的で安全なテンプレート文字列を使いこなせます。
