タイトル: シングルクォーテーションとダブルクォーテーションの違い
SEOタイトル: JavaScript の "" と '' の違い (仕様上は等価 / テンプレートリテラル / JSON / Lint)
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>JavaScript では <code>'hello'</code> と <code>"hello"</code> は<strong>仕様上完全に等価</strong>。型もコストも同じ</li><li>使い分けは<strong>チームの規約 (Prettier/ESLint)</strong> 次第。Airbnb は "'" (シングル) 推奨</li><li>バックティック <code>`...`</code> はテンプレートリテラル。<code>${expr}</code> 補間と複数行が可能</li><li><strong>JSON はダブルクォート必須</strong>。<code>'key': 1</code> はパースエラー</li><li>HTML 属性に埋め込むときは外側と逆を選ぶとエスケープ不要に</li></ul></td></tr></table>
<h2>結論: 仕様上は完全等価</h2>
<p>JavaScript の文字列リテラルは <code>'...'</code> と <code>"..."</code> のどちらでも <strong>同じ <code>string</code> 型の値</strong>を生成します。実行コストもメモリも違いはありません。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">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'</code></pre>
<h2>では何が違うのか</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>観点</th><th>シングル <code>'</code></th><th>ダブル <code>"</code></th><th>バックティック <code>`</code></th></tr></thead>
<tbody>
<tr><td>仕様上の挙動</td><td>同じ</td><td>同じ</td><td>テンプレートリテラル (拡張)</td></tr>
<tr><td>変数補間 <code>${x}</code></td><td>不可</td><td>不可</td><td>可</td></tr>
<tr><td>複数行</td><td>不可 (改行は <code>\n</code>)</td><td>不可</td><td>可</td></tr>
<tr><td>JSON で使えるか</td><td>不可 (パースエラー)</td><td>必須</td><td>不可</td></tr>
<tr><td>HTML 属性内</td><td><code>attr="..."</code> の中で安全</td><td><code>attr='...'</code> の中で安全</td><td>属性内では不要</td></tr>
<tr><td>慣習 (Airbnb/Standard)</td><td>★ 推奨</td><td>許容</td><td>補間時のみ</td></tr>
<tr><td>慣習 (Prettier 既定)</td><td>★ 既定 <code>singleQuote: true</code> も<br>4.0 までは <code>"</code></td><td>―</td><td>―</td></tr>
</tbody>
</table>
<h2>テンプレートリテラル: バックティックの真価</h2>
<p>変数を埋め込みたい / 複数行を書きたいときは、ES2015+ のバックティック <code>` `</code> を使います。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">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}`;</code></pre>
<h2>JSON はダブルクォート固定</h2>
<p>JSON 仕様 (RFC 8259) では文字列もキーも <strong>ダブルクォート必須</strong>。シングルは構文エラーになります。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ✅ 正しい 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}' (常にダブル)</code></pre>
<h2>HTML 属性に埋め込むときの選び方</h2>
<p>HTML 属性は <code>"..."</code> または <code>'...'</code> どちらでも書けます。<strong>外側と逆のクォートを内側で使う</strong>とエスケープを減らせます。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ✅ 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>;</code></pre>
<h2>エスケープシーケンスはどちらも同じ</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">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+)</code></pre>
<h2>ESLint / Prettier での強制</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-json">// .eslintrc.json - シングル強制
{
"rules": {
"quotes": ["error", "single", {
"avoidEscape": true,
"allowTemplateLiterals": true
}]
}
}
// .prettierrc - Prettier (デフォルトは "single": false = ダブル)
{
"singleQuote": true,
"jsxSingleQuote": false
}</code></pre>
<p>大事なのは<strong>チーム内で統一</strong>すること。<code>git diff</code> のノイズを減らすために、必ず Lint で自動修正できる状態を作っておきます。</p>
<h2>Python / PHP / Rust との違い</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>言語</th><th>差</th></tr></thead>
<tbody>
<tr><td>JavaScript</td><td>完全等価。バックティックでテンプレ</td></tr>
<tr><td>Python</td><td>完全等価。三重 <code>"""</code> / <code>'''</code> で複数行。f-string <code>f".."</code> で補間</td></tr>
<tr><td>PHP</td><td><strong>違いあり</strong>: <code>".."</code> は <code>$var</code> 補間あり、<code>'..'</code> は無し</td></tr>
<tr><td>Rust / Go / Java</td><td><code>".."</code> は文字列、<code>'..'</code> は <strong>char (1文字)</strong> なので意味が違う</td></tr>
<tr><td>Bash</td><td><code>".."</code> は変数展開あり、<code>'..'</code> は無し (PHP と同じ系)</td></tr>
</tbody>
</table>
<h2>FAQ</h2>
<p><strong>Q: どちらが速い?</strong><br />
A: 同じです。エンジン (V8/SpiderMonkey) は同じパースツリーに変換します。</p>
<p><strong>Q: いつバックティックを使うべき?</strong><br />
A: 変数補間が必要なときと複数行のとき。それ以外で乱用すると Lint が指摘します (<code>prefer-template</code>)。</p>
<p><strong>Q: minify 後はどうなる?</strong><br />
A: Terser などは出力時に統一します (既定は <code>"</code>)。バンドル後はチームの好みに依存しません。</p>