「文字列の結合が多くて見づらい…」
「HTMLのエスケープ処理って毎回どうすればいいんだろう?」
「バッククォートは使ってるけど、本当に正しく使えてるのかな」
前回はアロー関数とthisの振る舞いについて学びました。今回は、HTMLの生成をより簡潔に、安全に行うためのテンプレートリテラルについて解説します。
なぜテンプレートリテラルが必要か
まず、従来のHTML生成方法を振り返ってみましょう:
JS
// jQuery時代のHTML生成
var userHtml = '';
userHtml += '<div class="user-card">';
userHtml += ' <h2>' + user.name + '</h2>';
userHtml += ' <p class="email">' + user.email + '</p>';
userHtml += ' <p class="bio">' + user.bio + '</p>';
userHtml += '</div>';
$('#userList').append(userHtml);
この方法の問題点:
- 文字列結合が煩雑
- インデントが分かりにくい
- エスケープ処理が漏れやすい
- 可読性が低い
テンプレートリテラルの基本
JS
// モダンな書き方
const userHtml = `
<div class="user-card">
<h2>${user.name}</h2>
<p class="email">${user.email}</p>
<p class="bio">${user.bio}</p>
</div>
`;
document.querySelector('#userList').innerHTML = userHtml;
テンプレートリテラルの特徴:
- バッククォート(`)で囲む
- 複数行の記述が可能
- 式の埋め込みが${…}で簡単に
- HTMLの構造が視覚的に理解しやすい
実践的な使い方
1. 条件分岐の組み込み
JS
const cardHtml = `
<div class="user-card ${user.isAdmin ? 'admin' : ''}">
<h2>${user.name}</h2>
${user.isAdmin ? `
<span class="badge">管理者</span>
` : ''}
<p class="email">${user.email}</p>
</div>
`;
ポイント:
- 三項演算子で条件分岐を表現
- 入れ子のテンプレートリテラルも可能
- クラスの動的な追加が簡単
2. 繰り返し処理
JS
const users = [
{ name: 'John', email: 'john@example.com' },
{ name: 'Jane', email: 'jane@example.com' }
];
const userListHtml = `
<ul class="user-list">
${users.map(user => `
<li class="user-item">
<strong>${user.name}</strong>
<span>${user.email}</span>
</li>
`).join('')}
</ul>
`;
ポイント:
- map関数で配列を処理
- join(”)で配列を結合
- インデントが維持され可読性が高い
3. ヘルパー関数の活用
JS
const escape = str => str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
const userProfile = `
<div class="profile">
<h2>${escape(user.name)}</h2>
<p>${escape(user.bio)}</p>
</div>
`;
セキュリティ対策:
- XSS対策としてエスケープ処理
- ヘルパー関数で共通化
- 必要な箇所のみエスケープ
タグ付きテンプレート
JS
// タグ関数の定義
function html(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i - 1];
// 値がある場合はエスケープ処理
return result + (i > 0 ? escape(value) : '') + str;
});
}
// 使用例
const userCard = html`
<div class="user-card">
<h2>${user.name}</h2>
<p>${user.bio}</p>
</div>
`;
タグ付きテンプレートの利点:
- 自動的なエスケープ処理
- 値の加工や検証が可能
- 再利用可能な処理
コンポーネント化の例
JS
class UserCard {
constructor(user) {
this.user = user;
}
render() {
return `
<div class="user-card">
${this.renderHeader()}
${this.renderBody()}
${this.renderFooter()}
</div>
`;
}
renderHeader() {
return `
<header>
<h2>${escape(this.user.name)}</h2>
</header>
`;
}
renderBody() {
return `
<div class="card-body">
<p>${escape(this.user.bio)}</p>
</div>
`;
}
renderFooter() {
return `
<footer>
<a href="mailto:${escape(this.user.email)}">
連絡する
</a>
</footer>
`;
}
}
コンポーネント化のメリット:
- テンプレートの再利用が容易
- 責務の分割が明確
- メンテナンス性の向上
パフォーマンスの最適化
JS
// テンプレートの事前コンパイル
const template = values => `
<div class="user-card">
<h2>${values.name}</h2>
<p>${values.bio}</p>
</div>
`;
// 大量のデータを処理する場合
const fragment = document.createDocumentFragment();
users.forEach(user => {
const div = document.createElement('div');
div.innerHTML = template(user);
fragment.appendChild(div.firstChild);
});
document.querySelector('#userList').appendChild(fragment);
最適化のポイント:
- テンプレート関数の再利用
- DocumentFragmentの活用
- 必要最小限のDOM操作
まとめ
テンプレートリテラルを使うことで:
- HTML生成が直感的に
- メンテナンス性が向上
- セキュリティ対策が容易に
- コードの構造化が簡単に
次回は「クラス構文で整理する – オブジェクト指向プログラミングの現代的アプローチ」について解説し、より大規模なアプリケーション開発の手法を学んでいきましょう。