Лучший способ получить пересечение ключей двух объектов?

У меня есть два объектных литерала:

var firstObject =
{
    x: 0,
    y: 1,
    z: 2,

    a: 10,
    b: 20,
    e: 30
}

var secondObject =
{
    x: 0,
    y: 1,
    z: 2,

    a: 10,
    c: 20,
    d: 30
}

Я хочу получить пересечение ключей, эти два объектных литерала имеют следующий вид:

var intersectionKeys  = ['x', 'y', 'z', 'a']

Я, очевидно, могу сделать цикл и посмотреть, существует ли ключ с тем же именем в другом объекте, но мне интересно, будет ли это хорошим примером для некоторого функционального программирования и использования карты/фильтра/сокращения? Я сам не так много программировал, но у меня есть ощущение, что для этой проблемы может быть чистое и умное решение.

Ответы

Ответ 1

Решение без indexOf.

var firstObject = { x: 0, y: 1, z: 2, a: 10, b: 20, e: 30 },
    secondObject = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 };

function intersection(o1, o2) {
    return Object.keys(o1).concat(Object.keys(o2)).sort().reduce(function (r, a, i, aa) {
        if (i && aa[i - 1] === a) {
            r.push(a);
        }
        return r;
    }, []);
}

document.write('<pre>' + JSON.stringify(intersection(firstObject, secondObject), 0, 4) + '</pre>');

Ответ 2

Данные ответы хороши и удивительны, но в пустом ответе может быть проблема: "Что если одно из значений свойства намеренно установлено в undefined ".

Нина ответит хорошо (действительно фантастически), но, поскольку мы находимся на пороге завтрашнего дня в JavaScript, я думаю, что мой не будет слишком плох:

var a = { x: undefined, y: 1, z: 2, a: 10, b: 20, e: 30 }
var b = { x: 0, y: 1, z: 2, a: 10, c: 20, d: 30 }

function intersect(o1, o2){
    return Object.keys(o1).filter(k => k in o2)
}

document.write('<pre>' + JSON.stringify(intersect(a, b)) + '</pre>');

Ответ 3

Процедура, которую я предлагаю:

  • Получить array ключей, используя Object.keys() для одного из объектов.
  • Найти пересечение массива с помощью .filter и проверить, содержит ли второй объект ключ, соответствующий первому массиву.

var firstObject = {
  x: 0,
  y: 1,
  z: 2,

  a: 10,
  b: 20,
  e: 30
}

var secondObject = {
  x: 0,
  y: 1,
  z: 2,

  a: 10,
  c: 20,
  d: 30
}

function getIntKeys(obj1, obj2){

    var k1 = Object.keys(obj1);
    return k1.filter(function(x){
        return obj2[x] !== undefined;
    });
  
}

alert(getIntKeys(firstObject, secondObject));

Ответ 4

Рекурсивная функция

Это другое решение, может быть, вам поможет. Я использовал рекурсивную функцию для перехвата двух объектов. Преимущество этого решения заключается в том, что вам не нужно беспокоиться об атрибутах, которые являются объектами одновременно.

В этом случае функция перехватывает атрибуты, которые существуют в обоих объектах, и присваивает значение objSource как окончательное значение атрибута.

{
        function interceptObjects(objSource, objInterface) {
            let newObj = {};
            for (const key in objSource) {
                if (objInterface.hasOwnProperty(key)) {
                    // in javascript an array is a object too.
                    if (objSource[key] instanceof Object && !Array.isArray(objSource[key]) && objInterface[key] instanceof Object && !Array.isArray(objInterface[key])) {
                        newObj[key] = {};
                        newObj[key] = interceptObjects(objSource[key], objInterface[key])
                    } else {
                        newObj[key] = objSource[key];
                    }

                }
            }
            return newObj;
        }
        
        
        // FOR TESTING


    let objSource = {
            attr1: '',
            attr2: 2,
            attr3: [],
            attr4: {
                attr41: 'lol',
                attr42: 12,
                attr43: 15,
                attr45: [1, 4],
            },
            attr5: [2, 3, 4],
        };


        let objInterface = {
            attr1: null,
            attr4: {
                attr41: null,
                attr42: 12,
                attr45: [1],
            },
            attr5: [],
            attr6: null,
        };


        console.log(this.interceptObjects(objSource, objInterface));
    }