iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

【JavaScript】undefinedをスプレッド構文で展開するとどうなるか

はじめに

株式会社iimonでエンジニアをしているかとうです🦕

先に結論

undefinedをスプレッド構文で展開しようとすると以下の結果になります

結果 理由
オブジェクト
{ ...undefined }
✅ エラーにならない(無視される) スプレッド構文が undefinednull を無視するため
配列
[...undefined]
❌ エラーになる(TypeError undefined は反復可能ではないため

この記事でわかること

💡 オブジェクトでのスプレッド構文の性質

💡 配列でのスプレッド構文の性質

きっかけ

Github Copilotに次のようなコードに対して、レビューコメントをもらいました。

コード

const getDisplaySetting = (setting) => {
  if (!setting) return;
  return { setting };
};

// 後の処理でgetDisplaySettingメソッドをスプレッド構文を用いて展開

コメント

いままで、上記コードのように早期リターンを使用して、無意識にundefinedをスプレッド構文で展開していました😶💦

実行結果

1️⃣ settingがtrueの場合

const obj = {name: 'TEST'};
const result = {...obj, ...getDisplaySetting('SETTING')};
console.log(result); // { name: 'TEST', setting: 'SETTING' }

2️⃣ settingがfalse場合

const obj = {name: 'TEST'};
const result = {...obj, ...getDisplaySetting()};
console.log(result); // { name: 'TEST' }

undefinedをスプレッド構文で展開しても問題なさそう、、??😵‍💫💫

→ undefinedとスプレッド構文の関係を調べました

スプレッド構文

スプレッド構文とは

配列の要素やオブジェクトのプロパティを展開する構文のこと

配列内で展開可能

反復可能な値を展開することができる

const arr1 = [1, 2];
const arr2 = [...arr1, 3]; // [1, 2, 3]

🔍 詳しく

「反復可能な値(iterable)」とは、[Symbol.iterator]()メソッドを持つ値のことです。これを持っていることで、反復処理を可能にします。

[Symbol.iterator]()は、反復される必要があるときに呼び出される関数で、メソッドの返り値であるイテレーターは、反復される値を取得するために使用されます。

[Symbol.iterator]()メソッドを持つ値は何ができる?

  • 配列リテラルでスプレッド構文を用いて展開可能
  • for...ofを用いたループ処理が可能


反復可能な値
配列 ['a', 'b', 'c']
文字列 'hello'
Map new Map([['a', 1], ['b', 2]])
Set new Set([1, 2, 3])
NodeList document.querySelectorAll('div')

💡 for...ofループを使用できる値は、スプレッド構文を用いて配列内で展開可能!

オブジェクト内で展開可能

自身の列挙可能なプロパティを展開することができる

const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }

🔍 詳しく

「列挙可能なプロパティ」とは、for...in ループや Object.keys() で反復処理をすることができるプロパティのこと。

「自身のプロパティ」とは、プロトタイプから継承されたものでなく、そのオブジェクト自体が持っているプロパティのこと。

💡 for...inループを使用できる自身のプロパティは、スプレッド構文を用いてオブジェクト内で展開可能!

背景

ECMAScriptの仕様

ECMAScriptの仕様で、nullundefindedはオブジェクト内でスプレッド展開すると無視されるようになっています。

Null/Undefined Are Ignored

let emptyObject = { ...null, ...undefined }; // no runtime error

https://github.com/tc39/proposal-object-rest-spread/blob/main/Spread.md

プリミティブはオブジェクトに展開可能

mdnでプリミティブはオブジェクトに展開できると記述があり、nullundefindedが展開できることがわかります。

すべてのプリミティブはオブジェクトに展開できます。

スプレッド構文 - JavaScript | MDN

プリミティブ値とは?

オブジェクト以外の不変な値のこと

  • string
  • number
  • bigint
  • boolean
  • symbol
  • null
  • undefined

プリミティブ値のスプレッド展開例

オブジェクト内

const obj1 = { ...null };       // {}
const obj2 = { ...undefined };  // {}
const obj3 = { ...false };      // {}
const obj4 = { ...3 };          // {}
const obj5 = { ...'abc' };      // { 0: 'a', 1: 'b', 2: 'c' }

配列内

const arr1 = [...null];       // TypeError: null is not iterable
const arr2 = [...undefined];  // TypeError: undefined is not iterable
const arr3 = [...false];      // TypeError: false is not iterable
const arr4 = [...3];          // TypeError: 3 is not iterable
const arr5 = [...'abc'];      // ['a', 'b', 'c']

undefinedをスプレッド構文で展開する

オブジェクト内

オブジェクト内でundefinedをスプレッド構文で展開したとき

const obj = { ...undefined }; // {}

配列内

配列内でundefinedをスプレッド構文で展開したとき

const arr = [...undefined]; // TypeError: undefined is not iterable

配列内でスプレッド構文を用いて展開したい場合、対象が反復可能である必要がある

undefinedは反復可能な値ではないため、配列内で展開することができない

使用例

オブジェクト内でundefinedがスプレッド展開してもエラーが発生しないことを利用して、簡潔に安全な処理を書くことができます。

通常

const mergeUser = (setting) => {
  const user = { name: "NAME" };
  if (setting && setting.user) {
    console.log({ ...user, ...setting.user });
  } else {
    console.log(user);
  }
};
mergeUser(); // { name: 'NAME' }
mergeUser({ user: { age: 25 } }); // { name: 'NAME', age: 25 }

スプレッド構文とオプショナルチェーンを使用

const createUser = (setting) => {
  const user = {
    name: "NAME",
    ...setting?.user,
  }
  console.log(user);
}

createUser(); // { name: "NAME" }
createUser({ user: { age: 25 } }); // { name: "NAME", age: 30 }

setting または setting.userundefined になる場合でも、スプレッド構文がundefinedを無視するため、存在確認のための条件チェックなしにオブジェクトを結合することができます🌟

まとめ

  • オブジェクト内でのundefinednullのスプレッド展開

    → 無視される仕様のためエラーにならない

  • 配列内でのundefinednullのスプレッド展開

    → 反復可能ではないので展開できずにエラーになる

最後に

ここまで読んでいただきありがとうございます!🌷

弊社ではエンジニアを募集しています。

この記事を読んで少しでも興味を持ってくださった方は、ぜひカジュアル面談でお話ししましょう✨

iimon採用サイト / Wantedly / Green

参考