値と型と等価を理解する — JavaScript Tips
値には型があり、比較のルールも型とセットで決まります。typeof、===、null と undefined の違いが分かると、条件分岐やバグの多くが説明できます。DOM やフレームワークの話は範囲外です。
参考: MDN — データ型とデータ構造 · MDN — 等価演算子 · MDN — typeof
目次
プリミティブとオブジェクト
JavaScript の値は大きく プリミティブ(原始値) と オブジェクト(参照型) に分かれます。
| プリミティブ | 例 | 特徴 |
|---|---|---|
string |
"hello" |
文字列 |
number |
42, 3.14, NaN |
数値(整数・小数を区別しない) |
bigint |
100n |
大きな整数 |
boolean |
true, false |
真偽 |
undefined |
undefined |
未定義 |
symbol |
Symbol("id") |
一意の識別子 |
null |
null |
「値がない」ことを示す(型は object と報告される) |
オブジェクトは {}(オブジェクトリテラル)、[](配列)、function などです。プリミティブは値そのものをコピーし、オブジェクトは参照(住所のようなもの)を扱います。
let a = 10;let b = a;b = 20;console.log(a); // 10(a は変わらない)let obj1 = { x: 1 };let obj2 = obj1;obj2.x = 99;console.log(obj1.x); // 99(同じオブジェクトを指している)flowchart LR subgraph primitive["プリミティブ"] V1["a = 10"] V2["b = 20(別の値)"] end subgraph object["オブジェクト"] O["{ x: 99 }"] R1["obj1 ─┐"] R2["obj2 ─┘"] endtypeof で型を調べる
typeof は実行時に型を 文字列 で返す演算子です。
typeof "hello"; // "string"typeof 42; // "number"typeof true; // "boolean"typeof undefined; // "undefined"typeof Symbol(); // "symbol"typeof 10n; // "bigint"typeof null; // "object"(歴史的な仕様)typeof {}; // "object"typeof []; // "object"(配列も object)typeof function(){}; // "function"注意点
- 配列は
typeofでは"object"になる → 配列かどうかはArray.isArray(arr)を使う nullは"object"と出る →value === nullで判定する
const data = [1, 2, 3];console.log(Array.isArray(data)); // true学習中は REPL や console.log(typeof 値) で実際に確かめると体感がつきます。
厳密等価と抽象等価
| 演算子 | 名前 | 挙動 |
|---|---|---|
=== |
厳密等価 | 型も値も同じときだけ true |
== |
抽象等価 | 型が違えば 変換してから 比較 |
原則: 通常は === と !== だけを使う。 == は暗黙の型変換で意外な結果を生みます。
0 == false; // true(型変換)0 === false; // false"" == false; // true"" === false; // falsenull == undefined; // truenull === undefined; // false"42" == 42; // true"42" === 42; // false比較の指針
const age = 18;if (age === 18) { console.log("18歳");}const name = "";if (name !== "") { console.log("名前あり");}オブジェクト同士は 参照が同じか を比較します。中身が同じでも別オブジェクトなら false です。
console.log({ a: 1 } === { a: 1 }); // falseconst o = { a: 1 };const p = o;console.log(o === p); // truenull と undefined
undefined |
null |
|
|---|---|---|
| 意味 | 値がまだ代入されていない | 意図的に「空」を示す |
| 出どころ | 未初期化の変数、存在しないプロパティ、戻り値なし | 開発者が明示的に代入 |
let x;console.log(x); // undefinedconst user = { name: "太郎" };console.log(user.age); // undefined(プロパティがない)function noop() {}console.log(noop()); // undefinedlet selected = null; // まだ何も選ばれていないチェックの書き方
// undefined かどうかvalue === undefined;// null かどうかvalue === null;// null または undefined(どちらか)value == null; // 慣用句(== の数少ない用途)value === null || value === undefined;ざっくり言うと、undefined は「無い」、null は「空を選んだ」 です。?. や ?? は、その区別をコードに落とすための構文です。
よくある落とし穴
NaN は自分と等しくない
NaN === NaN; // falseNumber.isNaN(NaN); // true文字列の比較は辞書順
"10" < "2"; // true(文字列として比較)10 < 2; // false数値として比較するときは Number() や parseInt で変換します。
truthy / falsy
if では値が真偽に変換されます。
| falsy な値 |
|---|
false, 0, -0, 0n, "", null, undefined, NaN |
if ("0") { console.log("実行される"); // 空文字でなければ truthy}意図しない分岐を避けるには、条件を 明示的に 書きます(count === 0 や items.length > 0 など)。?? や ?. は falsy と nullish を分けたいときに使います。
if (count === 0) { /* ... */ }if (items.length > 0) { /* ... */ }まとめ表
| やりたいこと | 推奨 |
|---|---|
| 同値か比較 | === |
| 配列か判定 | Array.isArray() |
| NaN か判定 | Number.isNaN() |
| null / undefined | === で個別、または value == null |
よくある失敗
| 症状 | 原因の例 | 対処 |
|---|---|---|
if (x) なのに通らない |
x が 0 や "" で falsy |
x !== undefined など条件を具体化 |
同じ内容なのに === が false |
オブジェクトは参照比較 | 中身比較はループや専用関数が必要 |
typeof null が object |
言語仕様 | value === null で判定 |
== でバグ |
暗黙の型変換 | === に統一 |
undefined が増える |
存在しないキー、戻り値なし | デフォルト値やオプショナルチェーンを検討 |
関連: MDN — Truthy · MDN — Falsy