23.

JavaScriptのシングルとダブルクォートの違い|仕様上は等価・JSONは要ダブル

編集
この記事の要点
  • JavaScript では 'hello'"hello"仕様上完全に等価。型もコストも同じ
  • 使い分けはチームの規約 (Prettier/ESLint) 次第。Airbnb は "'" (シングル) 推奨
  • バックティック `...` はテンプレートリテラル。${expr} 補間と複数行が可能
  • JSON はダブルクォート必須'key': 1 はパースエラー
  • HTML 属性に埋め込むときは外側と逆を選ぶとエスケープ不要に

結論: 仕様上は完全等価

JavaScript の文字列リテラルは '...'"..." のどちらでも 同じ string 型の値を生成します。実行コストもメモリも違いはありません。

const a = 'hello';
const b = "hello";

console.log(a === b);           // true
console.log(typeof a);          // 'string'
console.log(typeof b);          // 'string'
console.log(a.length === b.length); // true

// 連結も同じ
console.log('foo' + "bar");     // 'foobar'

では何が違うのか

観点シングル 'ダブル "バックティック `
仕様上の挙動同じ同じテンプレートリテラル (拡張)
変数補間 ${x}不可不可
複数行不可 (改行は \n)不可
JSON で使えるか不可 (パースエラー)必須不可
HTML 属性内attr="..." の中で安全attr='...' の中で安全属性内では不要
慣習 (Airbnb/Standard)★ 推奨許容補間時のみ
慣習 (Prettier 既定)★ 既定 singleQuote: true
4.0 までは "

テンプレートリテラル: バックティックの真価

変数を埋め込みたい / 複数行を書きたいときは、ES2015+ のバックティック ` ` を使います。

const name = 'Alice';
const age = 30;

// ❌ 古いやり方 (連結)
const msg1 = 'Hello, ' + name + '! You are ' + age + ' years old.';

// ✅ テンプレートリテラル
const msg2 = `Hello, ${name}! You are ${age} years old.`;

// 複数行もそのまま書ける
const html = `
  <div class="user">
    <h2>${name}</h2>
    <p>Age: ${age}</p>
  </div>
`;

// 式も書ける
const tax = `Total: $${(price * 1.1).toFixed(2)}`;

// タグ付きテンプレート (高度)
function tag(strings, ...values) {
  return strings.raw.join('|') + ' / ' + values.join(',');
}
tag`Hi ${name} - ${age}`;

JSON はダブルクォート固定

JSON 仕様 (RFC 8259) では文字列もキーも ダブルクォート必須。シングルは構文エラーになります。

// ✅ 正しい JSON
const ok = '{"name":"Alice","age":30}';
JSON.parse(ok);          // { name: 'Alice', age: 30 }

// ❌ シングルクォートはエラー
const ng = "{'name':'Alice'}";
JSON.parse(ng);          // SyntaxError: Unexpected token ' in JSON at position 1

// JavaScript のオブジェクトリテラルとは別物
const obj = { name: 'Alice', age: 30 };   // ← JS なので OK
const jsonStr = JSON.stringify(obj);
// → '{"name":"Alice","age":30}' (常にダブル)

HTML 属性に埋め込むときの選び方

HTML 属性は "..." または '...' どちらでも書けます。外側と逆のクォートを内側で使うとエスケープを減らせます。

// ✅ HTML 属性が " なら JS は ' に
const html1 = '<a href="https://example.com" onclick="alert(\'hi\')">link</a>';
const html2 = `<a href="https://example.com" onclick='alert("hi")'>link</a>`;

// ❌ どちらも " だとエスケープ地獄
const ng = "<a href=\"https://example.com\" onclick=\"alert(\\\"hi\\\")\">link</a>";

// React / JSX
// 属性値は {} で式を渡せばクォート問題は出ない
const Btn = <button onClick={() => alert("hi")}>Go</button>;

エスケープシーケンスはどちらも同じ

const s1 = 'line1\nline2\ttab';
const s2 = "line1\nline2\ttab";
console.log(s1 === s2);   // true

// 含めたいクォートを逆で囲うとエスケープ不要
const a = "Bob's car";       // OK
const b = 'Bob\'s car';      // OK だがエスケープが必要
const c = 'She said "hi"';   // OK
const d = "She said \"hi\""; // OK だがエスケープが必要

// Unicode
const heart = '❤';      // ❤
const emoji = '\u{1F600}';   // 😀 (ES2015+)

ESLint / Prettier での強制

// .eslintrc.json - シングル強制
{
  "rules": {
    "quotes": ["error", "single", {
      "avoidEscape": true,
      "allowTemplateLiterals": true
    }]
  }
}

// .prettierrc - Prettier (デフォルトは "single": false = ダブル)
{
  "singleQuote": true,
  "jsxSingleQuote": false
}

大事なのはチーム内で統一すること。git diff のノイズを減らすために、必ず Lint で自動修正できる状態を作っておきます。

Python / PHP / Rust との違い

言語
JavaScript完全等価。バックティックでテンプレ
Python完全等価。三重 """ / ''' で複数行。f-string f".." で補間
PHP違いあり: ".."$var 補間あり、'..' は無し
Rust / Go / Java".." は文字列、'..'char (1文字) なので意味が違う
Bash".." は変数展開あり、'..' は無し (PHP と同じ系)

FAQ

Q: どちらが速い?
A: 同じです。エンジン (V8/SpiderMonkey) は同じパースツリーに変換します。

Q: いつバックティックを使うべき?
A: 変数補間が必要なときと複数行のとき。それ以外で乱用すると Lint が指摘します (prefer-template)。

Q: minify 後はどうなる?
A: Terser などは出力時に統一します (既定は ")。バンドル後はチームの好みに依存しません。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本的なルール
  2. 変数
  3. 演算子
  4. 標準ライブラリ
  5. 外部ライブラリ
  6. 制御構文
  7. リスト(配列)
  8. タプル
  9. セット
  10. 辞書(dict)
  11. クラスとメソッド
  12. 継承の概念と必要性
  13. 継承の構文
  14. コンストラクタ
  15. cookieの値の設定と取得
  16. 例外処理
  17. 例外を文字列で出力する方法
  18. httpリクエスト(curl)をする方法
  19. Responseオブジェクトの中身の確認
  20. 変数が空かどうか判定する方法
  21. タイムゾーンの設定と現在日時の取得と文字列化
  22. シングルクォーテーションとダブルクォーテーションの違い

最近更新/作成されたページ