Skip to content

Instantly share code, notes, and snippets.

@yukikim
Created November 17, 2024 22:18
Show Gist options
  • Save yukikim/639342d179776ba82e61fa8d8c759fd9 to your computer and use it in GitHub Desktop.
Save yukikim/639342d179776ba82e61fa8d8c759fd9 to your computer and use it in GitHub Desktop.
2つのオブジェクトを比較

JavaScriptで2つのオブジェクトを比較し、一方に存在しないプロパティや値を特定するには、以下のような方法を使えます。具体的には、オブジェクトのキーをループで調べる方法や、再帰的に比較する関数を作る方法があります。

以下は、基本的なプロパティの比較を行う例と、再帰的に比較する例を示します。


1. 基本的なプロパティの比較

以下の関数では、片方のオブジェクトに存在して他方にないプロパティを特定します。

function compareObjects(obj1, obj2) {
    const missingInObj2 = [];
    const missingInObj1 = [];

    // obj1にあってobj2にないプロパティ
    for (const key of Object.keys(obj1)) {
        if (!(key in obj2)) {
            missingInObj2.push(key);
        }
    }

    // obj2にあってobj1にないプロパティ
    for (const key of Object.keys(obj2)) {
        if (!(key in obj1)) {
            missingInObj1.push(key);
        }
    }

    return {
        missingInObj1, // obj1に存在しないプロパティ
        missingInObj2, // obj2に存在しないプロパティ
    };
}

// 使用例
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { b: 2, d: 4 };

console.log(compareObjects(obj1, obj2));
// 結果: { missingInObj1: [ 'a', 'c' ], missingInObj2: [ 'd' ] }

2. 再帰的にプロパティを比較

オブジェクトのプロパティがネストされている場合、再帰的に比較する関数を作る必要があります。

function compareObjectsRecursive(obj1, obj2, path = '') {
    const differences = [];

    const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
    for (const key of keys) {
        const fullPath = path ? `${path}.${key}` : key;

        if (!(key in obj1)) {
            differences.push({ type: 'missing_in_obj1', path: fullPath });
        } else if (!(key in obj2)) {
            differences.push({ type: 'missing_in_obj2', path: fullPath });
        } else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object' && obj1[key] !== null && obj2[key] !== null) {
            // 再帰的に比較
            differences.push(...compareObjectsRecursive(obj1[key], obj2[key], fullPath));
        } else if (obj1[key] !== obj2[key]) {
            differences.push({ type: 'value_mismatch', path: fullPath, obj1: obj1[key], obj2: obj2[key] });
        }
    }

    return differences;
}

// 使用例
const obj1 = { a: 1, b: { x: 10, y: 20 }, c: 3 };
const obj2 = { a: 1, b: { x: 15, z: 25 }, d: 4 };

console.log(compareObjectsRecursive(obj1, obj2));
/*
結果:
[
  { type: 'missing_in_obj1', path: 'b.z' },
  { type: 'missing_in_obj2', path: 'b.y' },
  { type: 'value_mismatch', path: 'b.x', obj1: 10, obj2: 15 },
  { type: 'missing_in_obj2', path: 'c' },
  { type: 'missing_in_obj1', path: 'd' }
]
*/

3. ライブラリを使用する方法

自分で実装せず、既存のライブラリを使いたい場合は以下を検討できます。

  • lodash_.difference_.isEqual を組み合わせて使う
  • deep-diff ライブラリを使う

例: deep-diff

npm install deep-diff
const { diff } = require('deep-diff');

const obj1 = { a: 1, b: { x: 10, y: 20 }, c: 3 };
const obj2 = { a: 1, b: { x: 15, z: 25 }, d: 4 };

const differences = diff(obj1, obj2);
console.log(differences);

このように、目的やデータの構造に応じて適切な方法を選んでください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment