404 Not Found

404 Not Found


nginx

JavaScriptのデータ型

データ型は実行できる操作を決定します。数値は算術を、文字列は結合を、ブール値は条件分岐をサポートします。型を理解することは、JSの最も有名な落とし穴を避ける助けになります。

JSのデータ型

JavaScriptには8つのデータ型があり、プリミティブ型参照型に分類されます:

プリミティブ型(7種類):String、Number、BigInt、Boolean、Undefined、Null、Symbol

参照型(1種類):Object(配列、関数、日付などはすべてObjectのサブタイプ)

プリミティブデータはスタックメモリに格納され、代入時に値がコピーされます。参照型データはヒープメモリに格納され、代入時に参照(アドレス)がコピーされます。この区別は後のレッスンで詳しく扱います。

typeof演算子

typeofはデータ型をチェックし、文字列を返す演算子です:

typeofの結果
"hello" "string"
42 "number"
9007199254740991n "bigint"
true "boolean"
undefined "undefined"
null "object"(歴史的なバグ)
{ } "object"
function(){} "function"

注意:typeof null"object"を返します。これはJS誕生時からの歴史的なバグで、修正することはできません(変更すると既存のコードが壊れるため)。覚えておきましょう。

文字列と数値の落とし穴

JSの+演算子は2つの目的を持ちます:数値の加算と文字列の結合です。+の片方が文字列の場合、JSはもう片方の値も文字列に変換します:

これはJSの最も有名な落とし穴の一つで、初心者は誰もが引っかかります。対策:計算前にNumber()parseInt()で明示的に変換することです。

nullとundefined

どちらも「値なし」を意味しますが、意図が異なります:

こう考えましょう:undefinedは家具のない新しい家で、nullは家具をわざとすべて運び出した状態です。

実例:さまざまな型でのtypeof

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JSデータ型 - typeof</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 600px; margin: 60px auto; }
    table { width: 100%; border-collapse: collapse; margin: 16px 0; }
    th, td { padding: 10px; text-align: left; border: 1px solid #ddd; }
    th { background: #2196F3; color: #fff; }
    button { margin-top: 12px; padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #2196F3; }
    #result { margin-top: 12px; padding: 16px; background: #f5f5f5; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; white-space: pre; }
  </style>
</head>
<body>
  <h2>typeof演算子</h2>
  <button id="testBtn">typeofテストを実行</button>
  <div id="result">ボタンをクリックしてtypeofの結果を確認</div>
  <script>
    document.getElementById("testBtn").onclick = function() {
      var a = "hello";
      var b = 42;
      var c = 9007199254740991n;
      var d = true;
      var e = undefined;
      var f = null;
      var g = {name: "太郎"};
      var h = [1, 2, 3];
      var i = function(){};
      var output = "";
      output += 'typeof "hello"  → "' + typeof a + '"\n';
      output += "typeof 42       → \"" + typeof b + '"\n';
      output += "typeof 9007199254740991n → \"" + typeof c + '"\n';
      output += "typeof true     → \"" + typeof d + '"\n';
      output += "typeof undefined → \"" + typeof e + '"\n';
      output += "typeof null     → \"" + typeof f + '"  ⚠️ 歴史的なバグ!\n';
      output += "typeof {}       → \"" + typeof g + '"\n';
      output += "typeof []       → \"" + typeof h + '"  (配列もobject)\n';
      output += 'typeof function → "' + typeof i + '"';
      document.getElementById("result").textContent = output;
    };
  </script>
</body>
</html>

実例:文字列と数値の落とし穴

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JSデータ型 - 文字列と数値の落とし穴</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 550px; margin: 60px auto; }
    .trap { background: #fff3e0; padding: 12px; border-radius: 8px; color: #E65100; border-left: 4px solid #FF9800; margin: 12px 0; }
    .safe { background: #e8f5e9; padding: 12px; border-radius: 8px; color: #2E7D32; border-left: 4px solid #4CAF50; margin: 12px 0; }
    .row { display: flex; justify-content: space-between; padding: 10px 16px; border-bottom: 1px solid #eee; font-family: Consolas, monospace; }
    .row:last-child { border-bottom: none; }
    .result-box { background: #f5f5f5; border-radius: 8px; margin: 12px 0; overflow: hidden; }
    .label { color: #666; }
    .value { font-weight: bold; }
    .bad { color: #f44336; }
    .good { color: #4CAF50; }
    button { margin-top: 12px; padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #e91e63; }
  </style>
</head>
<body>
  <h2>文字列 + 数値の落とし穴</h2>
  <p class="trap">⚠️ +の片方が文字列の場合、JSは加算ではなく結合を行います! "5"+3は8ではなく"53"になります</p>
  <button id="trapBtn">落とし穴デモを実行</button>
  <div class="result-box" id="trapResult">
    <div class="row"><span class="label">"5" + 3 =</span><span class="value" id="r1">?</span></div>
    <div class="row"><span class="label">5 + 3 =</span><span class="value" id="r2">?</span></div>
    <div class="row"><span class="label">"5" - 3 =</span><span class="value" id="r3">?</span></div>
    <div class="row"><span class="label">"5" * 3 =</span><span class="value" id="r4">?</span></div>
  </div>
  <p class="safe">✅ 対策:計算前にNumber()で明示的に変換する</p>
  <button id="safeBtn" style="background:#4CAF50;">安全なバージョンを実行</button>
  <div class="result-box" id="safeResult">
    <div class="row"><span class="label">Number("5") + 3 =</span><span class="value" id="s1">?</span></div>
  </div>
  <script>
    document.getElementById("trapBtn").onclick = function() {
      var r1 = "5" + 3;
      var r2 = 5 + 3;
      var r3 = "5" - 3;
      var r4 = "5" * 3;
      document.getElementById("r1").textContent = '"' + r1 + '"';
      document.getElementById("r1").className = "value bad";
      document.getElementById("r2").textContent = r2;
      document.getElementById("r2").className = "value good";
      document.getElementById("r3").textContent = r3;
      document.getElementById("r3").className = "value good";
      document.getElementById("r4").textContent = r4;
      document.getElementById("r4").className = "value good";
    };
    document.getElementById("safeBtn").onclick = function() {
      var s1 = Number("5") + 3;
      document.getElementById("s1").textContent = s1;
      document.getElementById("s1").className = "value good";
    };
  </script>
</body>
</html>

実例:nullとundefined

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JSデータ型 - nullとundefined</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 550px; margin: 60px auto; }
    .card { padding: 16px; border-radius: 8px; margin: 12px 0; }
    .undef { background: #e3f2fd; border-left: 4px solid #2196F3; }
    .nul { background: #f3e5f5; border-left: 4px solid #9C27B0; }
    .result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; white-space: pre; margin: 12px 0; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #9C27B0; margin: 6px; }
  </style>
</head>
<body>
  <h2>nullとundefined</h2>
  <div class="card undef">
    <strong>undefined</strong>:変数は宣言されたが代入されていない、またはプロパティが存在しない<br>
    意味:「まだ値が与えられていない」— 家具のない新しい家のようなもの
  </div>
  <div class="card nul">
    <strong>null</strong>:開発者が明示的に空に設定した<br>
    意味:「意図的に何もなしに設定した」— わざと家具をすべて運び出した状態
  </div>
  <button id="testBtn">比較テストを実行</button>
  <div class="result" id="output">ボタンをクリックして結果を確認</div>
  <script>
    document.getElementById("testBtn").onclick = function() {
      var a;
      var b = null;
      var c = {name: "太郎"};
      var output = "";
      output += "=== undefinedのケース ===\n";
      output += "var a;  → a = " + a + " (undefined)\n";
      output += "typeof a → \"" + typeof a + "\"\n";
      output += "c.age → " + c.age + " (存在しないプロパティもundefined)\n\n";
      output += "=== nullのケース ===\n";
      output += "var b = null;  → b = " + b + " (null)\n";
      output += "typeof b → \"" + typeof b + "\"  ⚠️ 歴史的なバグ\n\n";
      output += "=== 比較 ===\n";
      output += "null == undefined  → " + (null == undefined) + "  (緩い等価)\n";
      output += "null === undefined → " + (null === undefined) + "  (厳密な不等価)\n";
      output += "typeof null  → \"object\"  (バグ)\n";
      output += "typeof undefined → \"undefined\"  (正しい)\n\n";
      output += "結論: null === undefinedはfalse\n";
      output += "異なる意味を持ち、厳密比較では同じ値ではありません";
      document.getElementById("output").textContent = output;
    };
  </script>
</body>
</html>

実例:全データ型一覧

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JSデータ型 - 全データ型一覧</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 600px; margin: 60px auto; }
    .type-card { display: inline-block; width: 120px; padding: 16px; margin: 6px; border-radius: 10px; text-align: center; color: #fff; cursor: pointer; transition: transform 0.2s; }
    .type-card:hover { transform: scale(1.08); }
    .type-card h3 { margin: 0 0 4px; font-size: 14px; opacity: 0.9; }
    .type-card p { margin: 0; font-size: 12px; font-family: Consolas, monospace; }
    .string { background: #4CAF50; }
    .number { background: #2196F3; }
    .bigint { background: #e91e63; }
    .boolean { background: #FF9800; }
    .undef { background: #9E9E9E; }
    .nul { background: #795548; }
    .symbol { background: #00BCD4; }
    .object { background: #9C27B0; }
    #detail { margin-top: 20px; padding: 20px; background: #f5f5f5; border-radius: 8px; font-size: 16px; line-height: 1.8; display: none; }
  </style>
</head>
<body>
  <h2>JSの8つのデータ型</h2>
  <div class="type-card string" onclick="showDetail('string')"><h3>String</h3><p>"hello"</p></div>
  <div class="type-card number" onclick="showDetail('number')"><h3>Number</h3><p>42</p></div>
  <div class="type-card bigint" onclick="showDetail('bigint')"><h3>BigInt</h3><p>900n</p></div>
  <div class="type-card boolean" onclick="showDetail('boolean')"><h3>Boolean</h3><p>true</p></div>
  <div class="type-card undef" onclick="showDetail('undefined')"><h3>Undefined</h3><p>undefined</p></div>
  <div class="type-card nul" onclick="showDetail('null')"><h3>Null</h3><p>null</p></div>
  <div class="type-card symbol" onclick="showDetail('symbol')"><h3>Symbol</h3><p>Symbol()</p></div>
  <div class="type-card object" onclick="showDetail('object')"><h3>Object</h3><p>{key:"val"}</p></div>
  <div id="detail"></div>
  <script>
    function showDetail(type) {
      var detailEl = document.getElementById("detail");
      detailEl.style.display = "block";
      var info = {
        "string": "String\n引用符で囲まれたテキスト: \"hello\", 'world'\ntypeof → \"string\"\n+で結合可能",
        "number": "Number\n整数と小数: 42, 3.14, -7\n特殊な値: Infinity, -Infinity, NaN\ntypeof → \"number\"",
        "bigint": "BigInt\nNumberの安全な範囲を超える整数を表現\n構文: 数値の後にnを付ける(例: 9007199254740991n)\ntypeof → \"bigint\"",
        "boolean": "Boolean\n2つの値のみ: trueとfalse\n条件分岐でよく使用\ntypeof → \"boolean\"",
        "undefined": "Undefined\n宣言されたが代入されていない変数のデフォルト値\ntypeof → \"undefined\"\n「まだ値なし」を意味する",
        "null": "Null\n開発者が明示的に「空」に設定\ntypeof → \"object\"(歴史的なバグ!)\nnull === undefinedはfalse",
        "symbol": "Symbol\nES6で追加、一意の識別子を作成\nすべてのSymbol()は異なる\ntypeof → \"symbol\"\nオブジェクトのプロパティキーとしてよく使用",
        "object": "Object\n参照型、キーと値のペアを格納\n配列[]、関数、日付はすべてオブジェクト\ntypeof → \"object\""
      };
      detailEl.textContent = info[type];
    }
  </script>
</body>
</html>

📖 まとめ

  1. JSには8つのデータ型がある:7つのプリミティブ型 + 1つの参照型(Object)
  2. typeof演算子は型をチェックするが、typeof null"object"を返す — 歴史的なバグ
  3. +は文字列が絡むと結合になる — "5" + 38ではなく"53"になる
  4. nullは「意図的に空」、undefinedは「まだ値なし」 — 厳密には等しくない
  5. 計算前にNumber()parseInt()で明示的に変換し、暗黙の型変換の落とし穴を避ける
  6. 配列[]もtypeofでは"object"を返す — Array.isArray()で区別する

❓ よくある質問

Q なぜtypeof null"object"を返すのですか?
A これはJSの初版からの歴史的なバグです。当時、JSは下位ビットで型を識別しており、nullの下位ビットはすべてゼロで、オブジェクト識別子と同じだったため、誤分類されました。後で修正を試みましたが、変更すると既存のコードが多すぎるため壊れるので、バグは永久に残りました。基礎が曲がった建物のようなもの — 住人が多すぎて取り壊せません。
Q 値が配列かプレーンオブジェクトかをどう区別しますか?
A typeofは配列とオブジェクトの両方に"object"を返すため、区別できません。正しい方法はArray.isArray()です。例えば、Array.isArray([1,2])trueを返し、Array.isArray({})falseを返します。
Q NaNの型は何ですか?
A NaN(Not a Number)のtypeof NaN"number"を返します。さらに奇妙なことに、NaN === NaNfalseを返し、自分自身とも等しくありません。NaNのチェックにはisNaN()Number.isNaN()を使いましょう。

📝 演習

  1. 基礎:6つのプリミティブ型(String、Number、Boolean、Undefined、Null、Object)の変数を6つ宣言し、それぞれにtypeofを適用して、結果をページに表示してください。
  2. 中級:入力フィールドを持つページを作成してください。ユーザーが任意の値を入力すると、JSがtypeofで型を検出し、結果を表示します。数値、文字列、true、nullなどを入力して、typeofの出力を観察してみましょう。
  3. 上級:型変換のクイズページを作成してください。"1" + 2の結果やnull == undefinedがtrueかfalseかなど、型変換の知識を問う5つの選択肢問題を用意し、ユーザーが選択肢をクリックすると正解/不正解と説明を表示してください。
100%