JavaScript基礎 #6 文字列とテンプレートリテラル

#5 オブジェクトと配列 で、データをまとめる2つのデータ構造を見ました。今回の記事は — 文字列 という1つのテーマを深く掘り下げます。よく使うメソッド、テンプレートリテラル、そして正規表現の基本まで。

文字列を作る — 引用符の3種類 #

JavaScriptで文字列を作る引用符は3つあります。

3種類の文字列
const a = 'シングルクォート';
const b = "ダブルクォート";
const c = `バッククォート(テンプレートリテラル)`;

'(シングル)と "(ダブル)は意味的に違いはありません。チームのコンベンションに従って1種類に統一する のが普通です。このシリーズではシングルクォートを使います。

3つ目のバッククォートは テンプレートリテラル と呼ばれる強力な文字列の形ですが、後ほど詳しく見ます。

よく使うメソッド #

長さとインデックスアクセス #

基本情報
const s = 'ジャバスクリプト';

s.length;      // 8
s[0];          // 'ジ'
s.at(0);       // 'ジ'
s.at(-1);      // 'ト' (負のインデックス — at のみ可能)

at() はES2022で追加されたメソッドです。負のインデックスで末尾から アクセスできます。s[s.length - 1] より短くて明確です。

検索 #

検索 / 包含チェック
const s = 'hello world';

s.includes('world');     // true
s.indexOf('world');       // 6
s.indexOf('foo');         // -1 (なければ -1)
s.startsWith('hello');    // true
s.endsWith('world');      // true

検索はほぼ常に includes / startsWith / endsWith が直感的です。indexOf は位置まで知りたい場合だけ。

切り出し / 抽出 #

部分文字列
const s = 'hello world';

s.slice(0, 5);       // 'hello'
s.slice(6);          // 'world'
s.slice(-5);         // 'world' (末尾から5文字)
s.substring(0, 5);   // 'hello' (slice とほぼ同じ)

昔は substring/substr/slice が微妙に異なっていましたが、新しいコードでは slice 1つに統一する のが良いです。負のインデックスも受け付けて、最も直感的です。

変換 / 整形 #

変換
const s = '  Hello World  ';

s.trim();              // 'Hello World'
s.trimStart();         // 'Hello World  '
s.trimEnd();           // '  Hello World'
s.toLowerCase();       // '  hello world  '
s.toUpperCase();       // '  HELLO WORLD  '
s.replaceAll(' ', '_'); // '__Hello_World__'

replaceAll はES2021で追加されました。昔は replace(/g/) で正規表現を使う必要がありましたが、今では単純な置換ならこちらのほうがすっきりします。

分割 / 結合 #

split / join
const s = 'りんご,バナナ,ぶどう';

s.split(',');                 // ['りんご', 'バナナ', 'ぶどう']
['りんご', 'バナナ'].join(',');  // 'りんご,バナナ'

// 1文字ずつ
'hello'.split('');            // ['h', 'e', 'l', 'l', 'o']

// 空文字列で結合
['h', 'i'].join('');          // 'hi'

split('') で1文字ずつ分けると、ASCII以外の文字(絵文字など)で壊れることがあります。絵文字や漢字まで安全に分けるには、[...s] (spread)や Array.from(s) を使います。

Unicode で安全な分離
const s = 'a😀b';
s.split('');          // ['a', '\uD83D', '\uDE00', 'b']  ← 壊れる
[...s];               // ['a', '😀', 'b']
Array.from(s);        // ['a', '😀', 'b']

テンプレートリテラル — バッククォートの真価 #

+ で文字列を連結する場面は、ほぼすべてバッククォートのほうがすっきりします。

文字列の合成
const name = 'カーティス';
const age = 30;

// + 演算
const a = 'こんにちは、' + name + ' (' + age + ')';

// テンプレートリテラル
const b = `こんにちは、${name} (${age})`;

${...} の中にはどんな式でも入れられます。

const items = ['りんご', 'バナナ', 'ぶどう'];

`合計 ${items.length}個`;
`最初: ${items[0]}`;
`合計: ${1 + 2 + 3}`;
`状態: ${age >= 18 ? '成人' : '未成年'}`;

複数行の文字列 #

複数行
const html = `
  <div>
    <h1>タイトル</h1>
    <p>本文</p>
  </div>
`;

昔は '<div>\n<h1>...' のように \n で改行を直接書いていました。バッククォートなら、改行がそのまま入ります。

Tagged Template — 関数呼び出し #

少し高度な使い方です。バッククォートの前に関数を置くと、テンプレートがその関数の引数として渡されます。

tagged template
function highlight(strings, ...values) {
  return strings.reduce((acc, s, i) => {
    return acc + s + (values[i] !== undefined ? `[${values[i]}]` : '');
  }, '');
}

const name = 'カーティス';
const age = 30;
highlight`名前は ${name}、年齢は ${age} です`;
// '名前は [カーティス]、年齢は [30] です'

html のようなライブラリで、SQL/HTMLインジェクションを防ぐためによく使われるパターンです。最初は馴染みがなくても大丈夫です — 出会ったときに改めて詳しく見れば十分です。

数値 / 文字列の変換 #

数値と文字列の間
String(42);              // '42'
(42).toString();         // '42'
`${42}`;                 // '42' — 最もよくある慣用句

Number('42');             // 42
parseInt('42px');         // 42 — 先頭部分のみ
parseFloat('3.14');       // 3.14
+'42';                    // 42 — 単項 + 演算子

Number('abc');            // NaN
parseInt('abc');          // NaN

Number(...) は全体が数値でなければ NaN になります。parseInt/parseFloat先頭から可能な分だけ パースします。入力に 42px のような単位が付いている場合は、後者が向いています。

正規表現 — パターンマッチング #

/パターン/フラグ の形のリテラルです。

正規表現の基本
const re = /hello/i;       // 大文字小文字無視
'Hello World'.match(re);   // ['Hello', ...]
re.test('Hi');             // false
re.test('Hello');          // true

よく使うメタ文字 #

パターン意味
.任意の1文字
\d数字
\w単語文字(アルファベット / 数字 / _)
\s空白
^ / $行の先頭 / 末尾
+1回以上
*0回以上
?0回または1回
[abc]a, b, cのいずれか
(...)キャプチャグループ

よく使う場面 #

検査 / 抽出 / 置換
// メール形式をざっくり検査
/^[^@]+@[^@]+\.[^@]+$/.test('me@example.com');   // true

// 数字だけ抽出
'price: 1500円'.match(/\d+/);   // ['1500', ...]

// すべてのマッチ
'a1 b2 c3'.matchAll(/[a-z]\d/g);  // イテラブル

// 置換
'2026-05-04'.replace(/-/g, '/');  // '2026/05/04'

g フラグは すべてのマッチ を探すという意味(global)です。なければ最初の1つだけを探します。

キャプチャグループ #

キャプチャグループで分離
const date = '2026-05-04';
const m = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
// m: ['2026-05-04', '2026', '05', '04', ...]

const [, year, month, day] = m;
console.log(year, month, day);   // 2026 05 04

丸括弧 (...) の中の部分が キャプチャ されて結果の配列に一緒に入ります。名前付きグループも可能です。

名前付きキャプチャ
const m = '2026-05-04'.match(
  /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/
);
m.groups.year;    // '2026'
m.groups.month;   // '05'
m.groups.day;     // '04'

(?<名前>...) の形です。結果の groups から名前で取り出します。

正規表現が必要なとき / 不要なとき #

正規表現は強力ですが、読みづらくなりやすい です。次の場合は、正規表現より通常の文字列メソッドのほうがほぼ常に良いです。

これは正規表現を使う必要なし
// 単純検索
s.includes('foo');               // O
s.match(/foo/);                  // X (過剰)

// 開始/終了の検査
s.startsWith('http');            // O
s.match(/^http/);                // X

// 単純置換
s.replaceAll('foo', 'bar');      // O
s.replace(/foo/g, 'bar');        // X (過剰)

正規表現が輝くのは、パターンが可変だったり、キャプチャが必要な場合 — 日付やメールのような形式の検査、ログのパースなどです。

まとめ #

今回の記事で整理した内容:

  • 引用符の3種類 — '/" は意味が同じ、` はテンプレートリテラル
  • よく使うメソッド — length/at/includes/slice/split/join/replaceAll
  • Unicodeで安全な分割は [...s] または Array.from(s)
  • テンプレートリテラル — ${} の中に式、複数行の文字列
  • 変換 — String()/Number()/parseInt()+値 の慣用句
  • 正規表現の基本 — メタ文字、g フラグ、キャプチャグループ
  • 単純な検索・置換は、正規表現よりメソッドのほうが明確

次の記事(#7 モジュール)ではシリーズの最後に — コードを複数のファイルに分けるES Modules、import/export のパターンを整理します。

X