JavaScript/TypeScript

値と型と等価を理解する

4
  • JavaScript

値と型と等価を理解する — JavaScript Tips

値には型があり、比較のルールも型とセットで決まります。typeof===nullundefined の違いが分かると、条件分岐やバグの多くが説明できます。DOM やフレームワークの話は範囲外です。

参考: MDN — データ型とデータ構造 · MDN — 等価演算子 · MDN — typeof


目次

  1. プリミティブとオブジェクト
  2. typeof で型を調べる
  3. 厳密等価と抽象等価
  4. null と undefined
  5. よくある落とし穴
  6. よくある失敗

プリミティブとオブジェクト

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 ─┘"]  end

typeof で型を調べる

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); // true

null と 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 === 0items.length > 0 など)。???. は falsy と nullish を分けたいときに使います。

if (count === 0) { /* ... */ }if (items.length > 0) { /* ... */ }

まとめ表

やりたいこと 推奨
同値か比較 ===
配列か判定 Array.isArray()
NaN か判定 Number.isNaN()
null / undefined === で個別、または value == null

よくある失敗

症状 原因の例 対処
if (x) なのに通らない x0"" で falsy x !== undefined など条件を具体化
同じ内容なのに === が false オブジェクトは参照比較 中身比較はループや専用関数が必要
typeof null が object 言語仕様 value === null で判定
== でバグ 暗黙の型変換 === に統一
undefined が増える 存在しないキー、戻り値なし デフォルト値やオプショナルチェーンを検討

関連: MDN — Truthy · MDN — Falsy

シェア