JavaScript | 配列・オブジェクト:配列の検索・判定 – undefined 要素の扱い

JavaScript JavaScript
スポンサーリンク

undefined 要素とは何か

配列の「undefined 要素」は2種類あります。ここが重要です:値が undefined で“入っている要素”と、インデックスはあるのに“実際には値がない空スロット(疎配列)”です。両者は見た目が似ていて混同しやすいですが、メソッドの挙動が変わるため区別が必須です。


値としての undefined と空スロット(疎配列)の違い

値としての undefined(定義済みの空値)

const a = [undefined, 1];
console.log(a.length); // 2(2要素ある)
console.log(a[0]);     // undefined(“値”としての undefined)
JavaScript

この場合、0番目には“要素が存在し、その値が undefined”です。

空スロット(要素自体が存在しない)

const b = [];
b.length = 2;      // 長さだけ伸ばす(値は入れない)
console.log(b);    // [ <2 empty items> ] と表示されることが多い
console.log(b[0]); // undefined(読み出すと undefined に見えるが“無い”)
JavaScript

ここが重要です:b[0] は読み出せば undefined に見えますが“値がないスロット”。メソッドの通過・スキップ挙動に差が出ます。


実用的な見分け方と生成パターン

in 演算子でスロットの存在を確認

const a = [undefined]; // 値として undefined
const b = [];
b.length = 1;          // 空スロット

console.log(0 in a); // true(要素はある)
console.log(0 in b); // false(スロット自体が無い)
JavaScript

ここが重要です:in は「そのインデックスに要素が“存在するか”」を判定します。値が undefined かどうかではなく“スロットの有無”です。

疎配列はこうして生まれる

const sparse = Array(3); // [ <3 empty items> ]
// または
const s = [];
s[5] = "X"; // 0〜4 は空スロット
JavaScript

疎配列は、length だけ伸ばす、飛びインデックスに代入する、delete で要素を消す(splice ではなく)などで発生します。


メソッドごとの挙動差(ここが最重要)

forEach/map/filter は空スロットを“スキップ”する

const a = [undefined, 1];
const b = Array(2); // [ <2 empty items> ]

a.forEach((v, i) => console.log("A", i, v));
// A 0 undefined
// A 1 1

b.forEach((v, i) => console.log("B", i, v));
// 何も出力されない(空スロットはコールされない)
JavaScript

ここが重要です:値として undefined がある場合はコールバックが呼ばれます。空スロットは“存在しない”扱いでスキップされます。

map は長さを保つが、空スロットはそのまま空のまま

const b = Array(2);
const mapped = b.map(x => 0);
console.log(mapped); // [ <2 empty items> ](0 にはならない)
JavaScript

ここが重要です:空スロットはコールされないため、結果も“空のまま”。穴が埋まりません。

reduce は空スロットをスキップするが、初期値がないとエラーになる場合あり

const b = Array(2);
b.reduce((acc, x) => acc + (x ?? 0)); // TypeError(初期値が必要)
const sum = b.reduce((acc, x) => acc + (x ?? 0), 0); // 0(安全)
JavaScript

ここが重要です:空スロットをスキップするため、初期値がない reduce は“最初の要素”が見つからず失敗します。必ず初期値を置きましょう。

for…of と at は空スロットを“undefined として”扱う

const b = Array(2);
for (const v of b) console.log(v); // undefined, undefined(反復では undefined として出る)
console.log(b.at(0)); // undefined
JavaScript

ここが重要です:反復はスロットを辿る性質があり、undefined として現れます。forEach などの“スキップ”系と挙動が違う点に注意。


実務での安全な扱い方(穴を埋める・排除する)

疎配列を“通常の配列”へ正規化

const sparse = Array(3);
const normalized = Array.from(sparse, x => x ?? null); // [null, null, null]
JavaScript

ここが重要です:Array.from は空スロットにもマッピングを適用し、“存在する要素”として埋めます。null などに統一すると後工程が安定します。

undefined を安全に処理(デフォルト値を与える)

const xs = [undefined, 1, undefined];
const filled = xs.map(x => x ?? 0); // [0, 1, 0]
JavaScript

ここが重要です:null 合体演算子(??)で“null/undefined”にだけデフォルトを適用できます。0 や “” を誤って上書きしません。

欠損を取り除く(非破壊)

const xs = [undefined, 1, null, 2];
const compact = xs.filter(x => x != null); // [1, 2](null と undefined を除去)
JavaScript

ここが重要です:!= null は null と undefined の両方に一致する“安全な短縮”。0 や false は残せます。


生成・更新時の落とし穴と対策

delete を使わない(空スロットが生まれる)

const xs = [1, 2, 3];
delete xs[1];        // [1, <1 empty item>, 3](疎配列化)
xs.splice(1, 1);     // [1, 3](安全:疎配列を作らない)
JavaScript

ここが重要です:要素削除は splice を使い、疎配列を作らないのが鉄則です。

空配列を作るときは中身も初期化する

Array(3).fill(0);    // [0, 0, 0](空スロットを作らない)
Array.from({ length: 3 }, (_, i) => i); // [0, 1, 2]
JavaScript

ここが重要です:fill や Array.from で初期化しておくと、スキップ挙動に悩まされません。

比較・判定は“undefined と空スロットの違い”を意識

const arr = Array(1);
if (0 in arr) { /* スロットあり(値は空) */ } else { /* スロットなし */ }
JavaScript

ここが重要です:存在チェックは in、値チェックは x === undefined、目的に応じて使い分けます。


パターン別レシピ(よくある要件)

欠損をゼロ埋め

function zeroFill(arr) {
  return Array.from(arr, x => x ?? 0);
}
JavaScript

欠損を除去して詰める

function compact(arr) {
  // 空スロットも undefined も null も除去して詰める
  return arr.filter((_, i) => i in arr).filter(x => x != null);
}
JavaScript

疎配列を安全に map したい

const sparse = Array(3);
const mapped = Array.from(sparse, (_, i) => i * 2); // [0, 2, 4]
JavaScript

まとめ

undefined 要素の扱いで最も重要なのは「値としての undefined」と「空スロット(疎配列)」の区別です。in 演算子でスロットの有無を確認し、delete ではなく splice を使う、初期化には fill/Array.from を選ぶ。コールバック系メソッドは空スロットを“スキップ”するため、必要なら Array.from で正規化するか、null 合体(??)で安全に埋める。この基本を押さえれば、初心者でも欠損データに強い配列処理が安定して書けます。

タイトルとURLをコピーしました