タイトル: シングルクォーテーションとダブルクォーテーションの違い
SEOタイトル: JavaScript の "" と '' の違い (仕様上は等価 / テンプレートリテラル / JSON / Lint)
| この記事の要点 |
|
結論: 仕様上は完全等価
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 = `
${name}
Age: ${age}
`;
// 式も書ける
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 = 'link';
const html2 = `link`;
// ❌ どちらも " だとエスケープ地獄
const ng = "link";
// React / JSX
// 属性値は {} で式を渡せばクォート問題は出ない
const Btn = ;
エスケープシーケンスはどちらも同じ
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 などは出力時に統一します (既定は ")。バンドル後はチームの好みに依存しません。