Сравните два объекта, отфильтровывая определенные ключи. - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь найти лучший способ сделать это. Допустим, у меня есть два объекта

const baseObject = {
   firstName: "John",
   lastName: "Doe",
   dob: "01/01/00",
   siblings: []
}

const updatedObject = {
   firstName: "Johnathan",
   lastName: "Doe",
   dob: "01/01/00",
   siblings: []
}

Я хочу сравнить мой baseObject с моим updatedObject, опуская dob & siblings, чтобы найти какие-либо различия и изменения в другом объекте.

Я изо всех сил пытался как это сделать. Я играл с .filter, .map и т. Д. Без всяких оснований.

Примечание: Да [] действительно имеет значение.

Спасибо за любую помощь.

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

Так как вы хотите сравнить два объекта на ограниченных ключах, либо вам нужно специально упомянуть каждый ключ в условии условия, либо вам нужно поддерживать отдельную память для этих ключей. Если у вас меньше ключей excluding, сохраните массив для этого ключа для ключей including.

const baseObject = {
  firstName: "John",
  lastName: "Doe",
  dob: "01/01/00",
  siblings: []
}

const updatedObject = {
  firstName: "Johnathan",
  lastName: "Doe",
  dob: "01/01/00",
  siblings: []
}

// Excluding
function compareWithoutKeys(first = {}, second = {}, excludes = []) {
  return Object.entries(first).every(([key, value]) =>
    excludes.includes(key) ? true : second[key] === value
  )
}
compareWithoutKeys(baseObject, updatedObject, ['dob', 'siblings']) // true/false

// Including
function compareWithKeys(first = {}, second = {}, includes = []) {
  return Object.entries(first).every(([key, value]) =>
    includes.includes(key) ? second[key] === value : true
  )
}
compareWithKeys(baseObject, updatedObject, ['firstName', 'lastName']) // true/false

Обновление для сравнения не только строк.

Если вы хотите сравнить больше, чем строка, например, siblings (который является массивом), вы должны обновить функцию сравнения, вы проверите тип значения и затем сравните его соответствующим образом. Например, если значение равно Object, сравните каждый ключ или, если значение равно Array, сравните каждый индекс. Что-то вроде:

function isEqual(first, second) {
  const firstType = Object.prototype.toString.call(first)
  const secondType = Object.prototype.toString.call(second)

  if (firstType !=== secondType) {
    return false
  }

  switch (expression) {
    case '[object Array]': return first.every((value, index) => value === second[index])
    case '[object Object]': return Object.entries(first).every((value, index) => value === second[index])
    default: return first === second
  }
}

// Excluding
function compareWithoutKeys(first = {}, second = {}, excludes = []) {
  return Object.entries(first).every(([key, value]) =>
    excludes.includes(key) ? true : isEqual(value, second[key])
  )
}
// usage
compareWithoutKeys(baseObject, updatedObject, ['dob', 'siblings']) // true/false
compareWithoutKeys(baseObject, updatedObject, ['dob']) // true/false

// Including
function compareWithKeys(first = {}, second = {}, includes = []) {
  return Object.entries(first).every(([key, value]) =>
    includes.includes(key) ? isEqual(value, second[key]) : true
  )
}
// usage
compareWithKeys(baseObject, updatedObject, ['firstName', 'lastName']) // true/false
compareWithKeys(baseObject, updatedObject, ['firstName', 'lastName', 'siblings']) // true/false

Примечание: Это выполнит только первый уровень сравнения, если вы хотите выполнить глубокое сравнение уровней, например, возможно array of objects on which every key is an array, либо вы должны использовать рекурсивную функцию или отступление в такие библиотеки, как lodash .

Рекурсив может выглядеть примерно так, но я не проверял приведенный ниже код.

function isEqual(first, second) {
  const firstType = Object.prototype.toString.call(first)
  const secondType = Object.prototype.toString.call(second)

  if (firstType !=== secondType) {
    return false
  }

  switch (expression) {
    case '[object Array]': return first.every((value, index) => isEqual(second[index], value))
    case '[object Object]': return Object.entries(first).every((value, index) => isEqual(second[index], value))
    default: return first === second
  }
}

Статья о рекурсивной комбинации: https://gomakethings.com/check-if-two-arrays-or-objects-are-equal-with-javascript/

Лоэша: isEqual: https://lodash.com/docs/4.17.10#isEqual

0 голосов
/ 18 сентября 2018

Поскольку у вас есть плоский объект, и вы не хотите сравнивать массивы внутри (где последовательность будет иметь значение), вы можете stringify их игнорировать ненужные вам ключи и сравнивать строки.

const baseObject = {
    firstName: "John",
    lastName: "Doe",
    dob: "01/01/00",
    siblings: []
  },
  updatedObject1 = {
    firstName: "Johnathan",
    lastName: "Doe",
    dob: "01/01/00",
    siblings: []
  },
  updatedObject2 = {
    firstName: "John",
    lastName: "Doe",
    dob: "01/02/00",
    siblings: [10, 20]
  },
  keysToIgnore = ["dob", "siblings"],
  toJson = o => JSON.stringify(o, (k, v) => {
    if (!keysToIgnore.includes(k)) { return v }
  }),
  compare = (o1, o2) => toJson(o1)===toJson(o2);
  
  console.log('baseObject, updatedObject1: ' + compare(baseObject, updatedObject1));
  console.log('baseObject, updatedObject2: ' +compare(baseObject, updatedObject2));
0 голосов
/ 18 сентября 2018

Я бы предпочел не сравнивать каждое значение ключа объекта отдельно потому что со временем я бы ожидал, что мои объекты вырастут

Поиск различий в объектах javascript не так прост, если вы так думаете. Там нет волшебной функции (я много искал), которая может сделать это для вас. Вот почему вы должны перебирать ключи и делать все вручную.

Пример:

const changes = Object.keys(baseObject)
.filter(key => !['dob', 'siblings'].includes(key))
.map(key => (
  {
    property: key, 
    oldVal: baseObject[key], 
    newVal: updatedObject[key],
    wasUpdated: baseObject[key] === updatedObject[key]
  }
 ))

P.S. Вы не указали, как должен выглядеть результат, поэтому я написал код, не зная этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...